Restructure into brewpi/client/ws packages and add README
Splits the server, GUI client, and websocket layer into their own packages with dedicated requirements.txt files, and adds a README documenting the project's architecture and usage. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,251 @@
|
||||
# This is a sample Python script.
|
||||
import asyncio
|
||||
import sys
|
||||
from PyQt5 import QtGui, QtWidgets, QtCore
|
||||
from ws.client.ws_client import WsClient
|
||||
from ws.connection import IConnection
|
||||
import json
|
||||
from queue import Queue
|
||||
|
||||
|
||||
class Window(QtWidgets.QMainWindow, IConnection):
|
||||
|
||||
# Use signals and slots to avoid crashes
|
||||
# during updating gui elements from websocket context
|
||||
upd_progressbar_signal = QtCore.pyqtSignal(int, int)
|
||||
upd_color_signal = QtCore.pyqtSignal(str)
|
||||
|
||||
def __init__(self):
|
||||
QtWidgets.QMainWindow.__init__(self)
|
||||
self.ws_client = WsClient(self)
|
||||
self.is_exit_gracefully = True
|
||||
self.textEdit = None
|
||||
self.progressbar = []
|
||||
self.styleChoice = None
|
||||
|
||||
self.setGeometry(50, 50, 500, 300)
|
||||
self.setWindowTitle("Hallo Mausi!")
|
||||
self.setWindowIcon(QtGui.QIcon('res/flasche.png'))
|
||||
|
||||
self.menubar_create()
|
||||
self.statusbar_create()
|
||||
self.toolbar_create()
|
||||
self.buttons_create()
|
||||
self.checkbox_create()
|
||||
|
||||
self.progressbar_create()
|
||||
self.style_chooser_create()
|
||||
self.calendar_create()
|
||||
|
||||
self.send_data = Queue()
|
||||
self.show()
|
||||
|
||||
self.upd_progressbar_signal.connect(self.upd_progressbar_slot)
|
||||
self.upd_color_signal.connect(self.upd_color_slot)
|
||||
|
||||
def calendar_create(self):
|
||||
cal = QtWidgets.QCalendarWidget(self)
|
||||
cal.move(500, 200)
|
||||
cal.resize(250, 250)
|
||||
|
||||
def menubar_create(self):
|
||||
mainMenu = self.menuBar()
|
||||
fileMenu = mainMenu.addMenu("&File")
|
||||
|
||||
actionExit = QtWidgets.QAction("&Exit", self)
|
||||
actionExit.setShortcut("Ctrl+Q")
|
||||
actionExit.setStatusTip("Leave the App")
|
||||
actionExit.triggered.connect(self.on_btn_exit_clicked)
|
||||
|
||||
actionEditor = QtWidgets.QAction("&Editor", self)
|
||||
actionEditor.setShortcut("Ctrl+E")
|
||||
actionEditor.setStatusTip("Open Editor")
|
||||
actionEditor.triggered.connect(self.on_action_editor)
|
||||
|
||||
actionFileOpener = QtWidgets.QAction("File &Open", self)
|
||||
actionFileOpener.setShortcut("Ctrl+O")
|
||||
actionFileOpener.setStatusTip("Open a file")
|
||||
actionFileOpener.triggered.connect(self.on_action_file_open)
|
||||
|
||||
actionFileSaver = QtWidgets.QAction("File &Save", self)
|
||||
actionFileSaver.setShortcut("Ctrl+S")
|
||||
actionFileSaver.setStatusTip("Save a file")
|
||||
actionFileSaver.triggered.connect(self.on_action_file_save)
|
||||
|
||||
fileMenu.addAction(actionExit)
|
||||
fileMenu.addAction(actionEditor)
|
||||
fileMenu.addAction(actionFileOpener)
|
||||
fileMenu.addAction(actionFileSaver)
|
||||
|
||||
def statusbar_create(self):
|
||||
statusBar = self.statusBar()
|
||||
|
||||
def toolbar_create(self):
|
||||
def action_caller(a, n):
|
||||
return lambda action: self.on_action_triggered(a, n)
|
||||
|
||||
action1 = QtWidgets.QAction(QtGui.QIcon('res/glass.png'), "Drink a beer!", self)
|
||||
action1.triggered.connect(action_caller(action1, 1))
|
||||
|
||||
action2 = QtWidgets.QAction(QtGui.QIcon('res/glass2.png'), "Drink more beer!", self)
|
||||
action2.triggered.connect(action_caller(action2, 2))
|
||||
|
||||
action3 = QtWidgets.QAction(QtGui.QIcon('res/glass_flasche.png'), "Choose font!", self)
|
||||
action3.triggered.connect(self.on_action_font_triggered)
|
||||
|
||||
action4 = QtWidgets.QAction(QtGui.QIcon('res/dose.png'), "Choose color!", self)
|
||||
action4.triggered.connect(self.on_action_color_triggered)
|
||||
|
||||
toolbar = self.addToolBar("Toolbar")
|
||||
|
||||
toolbar.addAction(action1)
|
||||
toolbar.addAction(action2)
|
||||
toolbar.addAction(action3)
|
||||
toolbar.addAction(action4)
|
||||
|
||||
def buttons_create(self):
|
||||
btn = QtWidgets.QPushButton("Quit", self)
|
||||
btn.clicked.connect(self.on_btn_exit_clicked)
|
||||
btn.resize(btn.minimumSizeHint())
|
||||
btn.move(0, 100)
|
||||
|
||||
def checkbox_create(self):
|
||||
checkbox = QtWidgets.QCheckBox('Exit gracefully!', self)
|
||||
checkbox.stateChanged.connect(self.on_checkbox_changed)
|
||||
checkbox.setCheckState(2 if self.is_exit_gracefully else 0)
|
||||
checkbox.move(0, 150)
|
||||
|
||||
def progressbar_create(self):
|
||||
for i in range(0, 3):
|
||||
progressbar = QtWidgets.QProgressBar(self)
|
||||
progressbar.setGeometry(200, 80+25*i, 250, 20)
|
||||
self.progressbar.append(progressbar)
|
||||
|
||||
btn = QtWidgets.QPushButton("Download", self)
|
||||
btn.clicked.connect(self.on_btn_download_clicked)
|
||||
btn.move(0, 70)
|
||||
|
||||
def style_chooser_create(self):
|
||||
print(self.style().objectName())
|
||||
self.styleChoice = QtWidgets.QLabel("Linux", self)
|
||||
comboxBox = QtWidgets.QComboBox(self)
|
||||
comboxBox.addItem("motif")
|
||||
comboxBox.addItem("Windows")
|
||||
comboxBox.addItem("cde")
|
||||
comboxBox.addItem("Plastique")
|
||||
comboxBox.addItem("Cleanlooks")
|
||||
comboxBox.addItem("windowsvista")
|
||||
comboxBox.addItem("fusion")
|
||||
comboxBox.move(50, 250)
|
||||
self.styleChoice.move(150, 150)
|
||||
comboxBox.activated[str].connect(self.on_combobox_changed)
|
||||
|
||||
def on_btn_exit_clicked(self):
|
||||
print('PyQt5 on_btn_click')
|
||||
self.close()
|
||||
|
||||
def on_action_triggered(self, action, n):
|
||||
print('PyQt5 on_action_triggered {}'.format(n))
|
||||
if n == 1:
|
||||
self.ws_client.connect(uri="ws://localhost:8765")
|
||||
if n == 2:
|
||||
self.ws_client.disconnect()
|
||||
|
||||
def on_action_editor(self):
|
||||
self.textEdit = QtWidgets.QTextEdit()
|
||||
self.setCentralWidget(self.textEdit)
|
||||
|
||||
def on_action_file_open(self):
|
||||
name, _ = QtWidgets.QFileDialog.getOpenFileName(self, 'Open file')
|
||||
file = open(name, 'r')
|
||||
|
||||
self.on_action_editor()
|
||||
with file:
|
||||
text = file.read()
|
||||
self.textEdit.setText(text)
|
||||
|
||||
def on_action_file_save(self):
|
||||
|
||||
if self.textEdit is not None:
|
||||
name, _ = QtWidgets.QFileDialog.getSaveFileName(self, 'Save file')
|
||||
file = open(name, 'w')
|
||||
text = self.textEdit.toPlainText()
|
||||
file.write(text)
|
||||
file.close()
|
||||
else:
|
||||
print("No file to save!")
|
||||
|
||||
def on_action_font_triggered(self):
|
||||
font, valid = QtWidgets.QFontDialog.getFont()
|
||||
if valid:
|
||||
self.styleChoice.setFont(font)
|
||||
|
||||
def on_action_color_triggered(self):
|
||||
color = QtWidgets.QColorDialog.getColor()
|
||||
self.send_data.put({'Color': color.name()})
|
||||
|
||||
def on_checkbox_changed(self, state):
|
||||
print('PyQt5 on_checkbox_changed, state={}'.format(state))
|
||||
if state == QtCore.Qt.Checked:
|
||||
self.is_exit_gracefully = True
|
||||
else:
|
||||
self.is_exit_gracefully = False
|
||||
|
||||
def on_btn_download_clicked(self):
|
||||
print("Nothing happens!")
|
||||
|
||||
def on_combobox_changed(self, text):
|
||||
self.styleChoice.setText(text)
|
||||
QtWidgets.QApplication.setStyle(QtWidgets.QStyleFactory.create(text))
|
||||
|
||||
def on_connect(self):
|
||||
self.send_data.put_nowait({'+':'a'})
|
||||
self.send_data.put_nowait({'+':'b'})
|
||||
self.send_data.put_nowait({'+':'c'})
|
||||
self.send_data.put_nowait({'+':'Color'})
|
||||
|
||||
def on_disconnect(self):
|
||||
pass
|
||||
|
||||
@QtCore.pyqtSlot(int, int)
|
||||
def upd_progressbar_slot(self, n, v):
|
||||
self.progressbar[n].setValue(v)
|
||||
|
||||
@QtCore.pyqtSlot(str)
|
||||
def upd_color_slot(self, color_str):
|
||||
self.styleChoice.setStyleSheet("QWidget {background-color: %s}" % color_str)
|
||||
|
||||
async def on_recv(self, data):
|
||||
try:
|
||||
d = json.loads(data)
|
||||
keys = {'a': 0, 'b': 1, 'c': 2}
|
||||
color = {'Color': 0}
|
||||
for cmd in d:
|
||||
if cmd in keys.keys():
|
||||
await asyncio.get_event_loop().run_in_executor(None, self.upd_progressbar_signal.emit(keys[cmd], int(d[cmd] + 0.5)))
|
||||
|
||||
if cmd in color.keys():
|
||||
await asyncio.get_event_loop().run_in_executor(None, self.upd_color_signal.emit(d[cmd]))
|
||||
except:
|
||||
pass
|
||||
|
||||
async def on_send(self):
|
||||
try:
|
||||
data = await asyncio.get_event_loop().run_in_executor(None, self.send_data.get, True, 1)
|
||||
return data
|
||||
except:
|
||||
return None
|
||||
|
||||
def closeEvent(self, event):
|
||||
if self.is_exit_gracefully:
|
||||
print("Exitting gracefully!")
|
||||
self.ws_client.disconnect()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
app = QtWidgets.QApplication(sys.argv)
|
||||
|
||||
gui = Window()
|
||||
sys.exit(app.exec_())
|
||||
|
||||
# See PyCharm help at https://www.jetbrains.com/help/pycharm/
|
||||
Reference in New Issue
Block a user