using pyqtSignal in BaseHTTPRequestsHandler
-
I am using pyqt5 in a python3.9 environment and there is one simple but difficult problem for me. The main purpose is to run an http server using threads in pyqt5 and send a specific API request to that server. Using the BaseHttpRequestHandler class, we set it to throw a callback value only to APIs coming to a specific address. What I'm curious about here is, is it possible to use the value generated from BaseHttpRequestHandler inside MainWindow using pyqtSignal?
- What I want to do is to use this value in MainWindow when the value of screen_data is created in do_POST of the ResponseHandlerAdapter(BaseHTTPRequestHAndler) class. I would like to change the color of each row in the table using the data. *
here is my study code..
import sys import db import json import requests from datetime import datetime from PyQt5.QtGui import QColor from PyQt5.QtWidgets import QMainWindow, QApplication, QPushButton, QWidget, QTableWidgetItem, QHeaderView, QTableWidget from PyQt5.QtCore import Qt, pyqtSlot, QThread, QTimer, pyqtSignal, QObject from login_ui import Ui_Form from sidebar_ui import Ui_MainWindow from http.server import BaseHTTPRequestHandler, HTTPServer _URL = "*" _UpdateScreen_URL = "*" headers = { 'Content-Type': 'application/json', } port = * user = None screen_data = [] callback_data = [] class ApiServer(QThread): def __init__(self, parent=None): super().__init__(parent) self.parent = parent def run(self): http_server = HTTPServer(('', int(port)), ResponseHandlerAdapter) http_server.serve_forever() class ResponseHandlerAdapter(BaseHTTPRequestHandler): def do_POST(self): global screen_data, callback_data content = self.rfile.read(int(self.headers['content-length'])) resource = content.decode('utf8') self.send_response(200) self.end_headers() if self.path == '/led': pass elif self.path == '/screen': print("βββββββββ /SCREEN Response Data βββββββββ") screen_data.append(json.loads(resource)) print(screen_data) elif self.path == '/input': print("βββββββββ /INPUT CallBack Data βββββββββ") callback_data.append(json.loads(resource)) print(callback_data) class LoginScreen(QWidget, Ui_Form): def __init__(self): super(LoginScreen, self).__init__() self.setupLoginUi(self) self.login_btn.clicked.connect(self.login_function) def login_function(self): global user user = self.input_id.text() password = self.input_password.text() if len(user) == 0 or len(password) == 0: print("μμ΄λμ ν¨μ€μλλ₯Ό μ λ ₯ν΄μ£ΌμΈμ.") else: check_point = db.login(user, password) if check_point == password: print(f"[λ‘κ·ΈμΈ μ±κ³΅] [{user}]") self.hide() self.main = MainWindow() self.main.show() else: print("μμ΄λμ ν¨μ€μλλ₯Ό νμΈν΄μ£ΌμΈμ.") class MainWindow(QMainWindow): def __init__(self): super(MainWindow, self).__init__() self.ui = Ui_MainWindow() self.ui.setupUi(self) self.server = ApiServer(self) self.server.start() self.ui.icon_only_widget.hide() self.ui.stackedWidget.setCurrentIndex(0) self.ui.home_btn_2.setChecked(True) # λμ보λ λ©λ΄ κ΄λ ¨ self.ui.waybill_input.returnPressed.connect(self.select_data_from_waybill) self.ui.waybill_input.returnPressed.connect(self.send_data_to_tags) item = QTableWidgetItem() self.defaultBrush = (item.foreground(), item.background()) self.ui.db_table.itemChanged.connect(self.item_changed) self.set_table() self.ui.complete_btn_1.clicked.connect(self.set_clear) def handle_response(self, data): print(data) def set_clear(self): global user waybill_no = self.ui.waybill_input.text() self.ui.db_table.clear() self.ui.db_table.setRowCount(0) self.set_table() self.ui.waybill_input.clear() self.ui.waybill_input.setFocus() now = datetime.now().strftime('%Y-%m-%d %H:%M:%S') print(now) # db.update_picking_finish_time(user, now, waybill_no) print(user) ## ν μ΄λΈμμ 체ν¬λ°μ€ μ ν μ rowμμ λ³κ²½ def item_changed(self, item): if bool(item.checkState()): fg = QColor('#004000') bg = QColor('#C6EFCE') else: fg, bg = self.defaultBrush row = item.row() self.ui.db_table.itemChanged.disconnect() for col in range(self.ui.db_table.columnCount()): item = self.ui.db_table.item(row, col) if item: item.setForeground(fg) item.setBackground(bg) self.ui.db_table.itemChanged.connect(self.item_changed) ## Function for searching def on_search_btn_clicked(self): self.ui.stackedWidget.setCurrentIndex(5) search_text = self.ui.search_input.text().strip() if search_text: self.ui.label_9.setText(search_text) ## Function for changing page to user page def on_user_btn_clicked(self): self.ui.stackedWidget.setCurrentIndex(6) ## Change QPushButton Checkable status when stackWidget index changed def on_stackedWidget_currentChanged(self, index): btn_list = self.ui.icon_only_widget.findChildren(QPushButton) + self.ui.full_menu_widget.findChildren(QPushButton) for btn in btn_list: if index in [5, 6]: btn.setAutoExclusive(False) btn.setChecked(False) else: btn.setAutoExclusive(True) ## functions for changing menu page def on_home_btn_1_toggled(self): self.ui.stackedWidget.setCurrentIndex(0) def on_home_btn_2_toggled(self): self.ui.stackedWidget.setCurrentIndex(0) def on_dashboard_btn_1_toggled(self): self.ui.stackedWidget.setCurrentIndex(1) def on_dashboard_btn_2_toggled(self): self.ui.stackedWidget.setCurrentIndex(1) def on_work_btn_1_toggled(self): self.ui.stackedWidget.setCurrentIndex(2) def on_work_btn_2_toggled(self): self.ui.stackedWidget.setCurrentIndex(2) def on_product_btn_1_toggled(self): self.ui.stackedWidget.setCurrentIndex(3) def on_product_btn_2_toggled(self): self.ui.stackedWidget.setCurrentIndex(3) def on_userlist_btn_1_toggled(self): self.ui.stackedWidget.setCurrentIndex(4) def on_userlist_btn_2_toggled(self): self.ui.stackedWidget.setCurrentIndex(4) ## QtableWeidget μ€μ def set_table(self): self.ui.db_table.setColumnCount(9) self.ui.db_table.setHorizontalHeaderLabels( ['*', '*', '*', '*', '*', '*', '*', '*', '*'] ) ## μ΄μ‘μ₯ μ€μΊλ ν μν°ν€ ꡬν # 682679951842 def select_data_from_waybill(self): waybill_no = self.ui.waybill_input.text() print(waybill_no) rows = db.select_from_order_with_waybill(waybill_no) count = len(rows) self.ui.db_table.setRowCount(count) for x in range(count): for y in range(len(rows[x])): item = QTableWidgetItem() item.setText(str(rows[x][y])) if y == 0: item.setCheckState(False) self.ui.db_table.setItem(x, y, item) width = [] for column in range(self.ui.db_table.horizontalHeader().count()): self.ui.db_table.horizontalHeader().setSectionResizeMode(column, QHeaderView.ResizeToContents) width.append(self.ui.db_table.horizontalHeader().sectionSize(column)) def send_data_to_tags(self): # global screen_data waybill_no = self.ui.waybill_input.text() rows = db.select_from_mac(waybill_no) update_data = [] for row in rows: mac = row[5] ea = row[3] update_pre_data = {"mac": mac, "mappingtype": 574, "styleid": 48, "ledrgb": "ff00", "ledstate": "0", "outtime": "0", "EA": ea, "text_company": "copyright(C) by sd-da, All right Reserved."} update_data.append(update_pre_data) response = requests.post(_UpdateScreen_URL, headers=headers, data= json.dumps(update_data)) if response.status_code == 200: print('API success') print('μλ΅ λ΄μ©:', response.json()) else: print('API failed') print('μν μ½λ:', response.status_code) print('μλ΅ λ΄μ©:', response.text) if __name__ == "__main__": login_app = QApplication(sys.argv) login = LoginScreen() login.show() login_app.exec_()
- What I want to do is to use this value in MainWindow when the value of screen_data is created in do_POST of the ResponseHandlerAdapter(BaseHTTPRequestHAndler) class. I would like to change the color of each row in the table using the data. *
-
I am using pyqt5 in a python3.9 environment and there is one simple but difficult problem for me. The main purpose is to run an http server using threads in pyqt5 and send a specific API request to that server. Using the BaseHttpRequestHandler class, we set it to throw a callback value only to APIs coming to a specific address. What I'm curious about here is, is it possible to use the value generated from BaseHttpRequestHandler inside MainWindow using pyqtSignal?
- What I want to do is to use this value in MainWindow when the value of screen_data is created in do_POST of the ResponseHandlerAdapter(BaseHTTPRequestHAndler) class. I would like to change the color of each row in the table using the data. *
here is my study code..
import sys import db import json import requests from datetime import datetime from PyQt5.QtGui import QColor from PyQt5.QtWidgets import QMainWindow, QApplication, QPushButton, QWidget, QTableWidgetItem, QHeaderView, QTableWidget from PyQt5.QtCore import Qt, pyqtSlot, QThread, QTimer, pyqtSignal, QObject from login_ui import Ui_Form from sidebar_ui import Ui_MainWindow from http.server import BaseHTTPRequestHandler, HTTPServer _URL = "*" _UpdateScreen_URL = "*" headers = { 'Content-Type': 'application/json', } port = * user = None screen_data = [] callback_data = [] class ApiServer(QThread): def __init__(self, parent=None): super().__init__(parent) self.parent = parent def run(self): http_server = HTTPServer(('', int(port)), ResponseHandlerAdapter) http_server.serve_forever() class ResponseHandlerAdapter(BaseHTTPRequestHandler): def do_POST(self): global screen_data, callback_data content = self.rfile.read(int(self.headers['content-length'])) resource = content.decode('utf8') self.send_response(200) self.end_headers() if self.path == '/led': pass elif self.path == '/screen': print("βββββββββ /SCREEN Response Data βββββββββ") screen_data.append(json.loads(resource)) print(screen_data) elif self.path == '/input': print("βββββββββ /INPUT CallBack Data βββββββββ") callback_data.append(json.loads(resource)) print(callback_data) class LoginScreen(QWidget, Ui_Form): def __init__(self): super(LoginScreen, self).__init__() self.setupLoginUi(self) self.login_btn.clicked.connect(self.login_function) def login_function(self): global user user = self.input_id.text() password = self.input_password.text() if len(user) == 0 or len(password) == 0: print("μμ΄λμ ν¨μ€μλλ₯Ό μ λ ₯ν΄μ£ΌμΈμ.") else: check_point = db.login(user, password) if check_point == password: print(f"[λ‘κ·ΈμΈ μ±κ³΅] [{user}]") self.hide() self.main = MainWindow() self.main.show() else: print("μμ΄λμ ν¨μ€μλλ₯Ό νμΈν΄μ£ΌμΈμ.") class MainWindow(QMainWindow): def __init__(self): super(MainWindow, self).__init__() self.ui = Ui_MainWindow() self.ui.setupUi(self) self.server = ApiServer(self) self.server.start() self.ui.icon_only_widget.hide() self.ui.stackedWidget.setCurrentIndex(0) self.ui.home_btn_2.setChecked(True) # λμ보λ λ©λ΄ κ΄λ ¨ self.ui.waybill_input.returnPressed.connect(self.select_data_from_waybill) self.ui.waybill_input.returnPressed.connect(self.send_data_to_tags) item = QTableWidgetItem() self.defaultBrush = (item.foreground(), item.background()) self.ui.db_table.itemChanged.connect(self.item_changed) self.set_table() self.ui.complete_btn_1.clicked.connect(self.set_clear) def handle_response(self, data): print(data) def set_clear(self): global user waybill_no = self.ui.waybill_input.text() self.ui.db_table.clear() self.ui.db_table.setRowCount(0) self.set_table() self.ui.waybill_input.clear() self.ui.waybill_input.setFocus() now = datetime.now().strftime('%Y-%m-%d %H:%M:%S') print(now) # db.update_picking_finish_time(user, now, waybill_no) print(user) ## ν μ΄λΈμμ 체ν¬λ°μ€ μ ν μ rowμμ λ³κ²½ def item_changed(self, item): if bool(item.checkState()): fg = QColor('#004000') bg = QColor('#C6EFCE') else: fg, bg = self.defaultBrush row = item.row() self.ui.db_table.itemChanged.disconnect() for col in range(self.ui.db_table.columnCount()): item = self.ui.db_table.item(row, col) if item: item.setForeground(fg) item.setBackground(bg) self.ui.db_table.itemChanged.connect(self.item_changed) ## Function for searching def on_search_btn_clicked(self): self.ui.stackedWidget.setCurrentIndex(5) search_text = self.ui.search_input.text().strip() if search_text: self.ui.label_9.setText(search_text) ## Function for changing page to user page def on_user_btn_clicked(self): self.ui.stackedWidget.setCurrentIndex(6) ## Change QPushButton Checkable status when stackWidget index changed def on_stackedWidget_currentChanged(self, index): btn_list = self.ui.icon_only_widget.findChildren(QPushButton) + self.ui.full_menu_widget.findChildren(QPushButton) for btn in btn_list: if index in [5, 6]: btn.setAutoExclusive(False) btn.setChecked(False) else: btn.setAutoExclusive(True) ## functions for changing menu page def on_home_btn_1_toggled(self): self.ui.stackedWidget.setCurrentIndex(0) def on_home_btn_2_toggled(self): self.ui.stackedWidget.setCurrentIndex(0) def on_dashboard_btn_1_toggled(self): self.ui.stackedWidget.setCurrentIndex(1) def on_dashboard_btn_2_toggled(self): self.ui.stackedWidget.setCurrentIndex(1) def on_work_btn_1_toggled(self): self.ui.stackedWidget.setCurrentIndex(2) def on_work_btn_2_toggled(self): self.ui.stackedWidget.setCurrentIndex(2) def on_product_btn_1_toggled(self): self.ui.stackedWidget.setCurrentIndex(3) def on_product_btn_2_toggled(self): self.ui.stackedWidget.setCurrentIndex(3) def on_userlist_btn_1_toggled(self): self.ui.stackedWidget.setCurrentIndex(4) def on_userlist_btn_2_toggled(self): self.ui.stackedWidget.setCurrentIndex(4) ## QtableWeidget μ€μ def set_table(self): self.ui.db_table.setColumnCount(9) self.ui.db_table.setHorizontalHeaderLabels( ['*', '*', '*', '*', '*', '*', '*', '*', '*'] ) ## μ΄μ‘μ₯ μ€μΊλ ν μν°ν€ ꡬν # 682679951842 def select_data_from_waybill(self): waybill_no = self.ui.waybill_input.text() print(waybill_no) rows = db.select_from_order_with_waybill(waybill_no) count = len(rows) self.ui.db_table.setRowCount(count) for x in range(count): for y in range(len(rows[x])): item = QTableWidgetItem() item.setText(str(rows[x][y])) if y == 0: item.setCheckState(False) self.ui.db_table.setItem(x, y, item) width = [] for column in range(self.ui.db_table.horizontalHeader().count()): self.ui.db_table.horizontalHeader().setSectionResizeMode(column, QHeaderView.ResizeToContents) width.append(self.ui.db_table.horizontalHeader().sectionSize(column)) def send_data_to_tags(self): # global screen_data waybill_no = self.ui.waybill_input.text() rows = db.select_from_mac(waybill_no) update_data = [] for row in rows: mac = row[5] ea = row[3] update_pre_data = {"mac": mac, "mappingtype": 574, "styleid": 48, "ledrgb": "ff00", "ledstate": "0", "outtime": "0", "EA": ea, "text_company": "copyright(C) by sd-da, All right Reserved."} update_data.append(update_pre_data) response = requests.post(_UpdateScreen_URL, headers=headers, data= json.dumps(update_data)) if response.status_code == 200: print('API success') print('μλ΅ λ΄μ©:', response.json()) else: print('API failed') print('μν μ½λ:', response.status_code) print('μλ΅ λ΄μ©:', response.text) if __name__ == "__main__": login_app = QApplication(sys.argv) login = LoginScreen() login.show() login_app.exec_()
@check_f The usual way in Qt to exchange data inside an application is to use signals/slots. So, you thread can emit a signal and pass the data you need in MainWindow as signal parameter. In MainWindow you connect a slot to this signal and do whatever you need with received data.
- What I want to do is to use this value in MainWindow when the value of screen_data is created in do_POST of the ResponseHandlerAdapter(BaseHTTPRequestHAndler) class. I would like to change the color of each row in the table using the data. *
-
@check_f The usual way in Qt to exchange data inside an application is to use signals/slots. So, you thread can emit a signal and pass the data you need in MainWindow as signal parameter. In MainWindow you connect a slot to this signal and do whatever you need with received data.
@jsulm As you advised, I created a signal in the thread ApiServer class and output the slot in the MainWindow class, but it did not work. Maybe I'm confusing something?
my code:class ApiServer(QThread): server_signal = pyqtSignal(int) def __init__(self, parent=None): super().__init__(parent) self.parent = parent self.server_signal.emit(1) def run(self): http_server = HTTPServer(('', int(port)), ResponseHandlerAdapter) http_server.serve_forever() class MainWindow(QMainWindow): def __init__(self): super(MainWindow, self).__init__() self.ui = Ui_MainWindow() self.ui.setupUi(self) self.server = ApiServer(self) self.server.start() self.ui.icon_only_widget.hide() self.ui.stackedWidget.setCurrentIndex(0) self.ui.home_btn_2.setChecked(True) # λμ보λ λ©λ΄ κ΄λ ¨ self.ui.waybill_input.returnPressed.connect(self.select_data_from_waybill) self.ui.waybill_input.returnPressed.connect(self.send_data_to_tags) self.server.server_signal.connect(self.handle_response) item = QTableWidgetItem() self.defaultBrush = (item.foreground(), item.background()) self.ui.db_table.itemChanged.connect(self.item_changed) self.set_table() self.ui.complete_btn_1.clicked.connect(self.set_clear) def handle_response(self, data): print("signal ok")
-
@jsulm As you advised, I created a signal in the thread ApiServer class and output the slot in the MainWindow class, but it did not work. Maybe I'm confusing something?
my code:class ApiServer(QThread): server_signal = pyqtSignal(int) def __init__(self, parent=None): super().__init__(parent) self.parent = parent self.server_signal.emit(1) def run(self): http_server = HTTPServer(('', int(port)), ResponseHandlerAdapter) http_server.serve_forever() class MainWindow(QMainWindow): def __init__(self): super(MainWindow, self).__init__() self.ui = Ui_MainWindow() self.ui.setupUi(self) self.server = ApiServer(self) self.server.start() self.ui.icon_only_widget.hide() self.ui.stackedWidget.setCurrentIndex(0) self.ui.home_btn_2.setChecked(True) # λμ보λ λ©λ΄ κ΄λ ¨ self.ui.waybill_input.returnPressed.connect(self.select_data_from_waybill) self.ui.waybill_input.returnPressed.connect(self.send_data_to_tags) self.server.server_signal.connect(self.handle_response) item = QTableWidgetItem() self.defaultBrush = (item.foreground(), item.background()) self.ui.db_table.itemChanged.connect(self.item_changed) self.set_table() self.ui.complete_btn_1.clicked.connect(self.set_clear) def handle_response(self, data): print("signal ok")
-
@check_f You're emitting the signal in the constructor - at that time the slot is not yet connected, so why do you expect this to work?
@jsulm Sorry, I think I still have little understanding of "Class".
What I want is for a signal to be fired when the do_POST function is executed in the ResponseHandlerAdapter() class. So, is it correct to create a signal in that class? If there is another location, I would appreciate it if you could let me know. -
@jsulm Sorry, I think I still have little understanding of "Class".
What I want is for a signal to be fired when the do_POST function is executed in the ResponseHandlerAdapter() class. So, is it correct to create a signal in that class? If there is another location, I would appreciate it if you could let me know.@check_f I did not say that you placed your signal in the wrong class. I said that EMITTING the signal in the CONSTRUCTOR is wrong, because while the constructor is being executed the connection between signal and slot was not yet established.
"What I want is for a signal to be fired when the do_POST function is executed" - then emit the signal there instead of constructor...
-
@check_f I did not say that you placed your signal in the wrong class. I said that EMITTING the signal in the CONSTRUCTOR is wrong, because while the constructor is being executed the connection between signal and slot was not yet established.
"What I want is for a signal to be fired when the do_POST function is executed" - then emit the signal there instead of constructor...
-
@jsulm
Sorry, but can you give me an example using the code above? I don't know well..π₯π₯@check_f Did you read https://wiki.qt.io/Qt_for_Python_Signals_and_Slots already? If not then please do.
-
@check_f Did you read https://wiki.qt.io/Qt_for_Python_Signals_and_Slots already? If not then please do.