Skip to content

Commit fe557a3

Browse files
mcagriaksoymcagriaksoy
authored andcommitted
v1.4.0 changes, ui updated, new functionality, better theme handling
1 parent fe8c51e commit fe557a3

File tree

7 files changed

+1071
-831
lines changed

7 files changed

+1071
-831
lines changed

README.md

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -38,20 +38,13 @@ The COM port tool is compatible with:
3838
[![OS - Linux](https://img.shields.io/badge/OS-Linux-blue?logo=linux&logoColor=white)](https://www.linux.org/ "Go to Linux homepage")
3939
[![OS - Windows](https://img.shields.io/badge/OS-Windows-blue?logo=windows&logoColor=white)](https://www.microsoft.com/ "Go to Microsoft homepage")
4040

41-
To use the tool, follow these steps:
42-
First of all, please ensure that you installed dependencies already.
41+
1. Run the program.
42+
2. Select a serial port and configure parameters.
43+
3. Start communication using the **Start** button.
44+
4. Send or receive data as needed.
45+
5. Save received data or clear buffers using the respective buttons.
4346

44-
```
45-
python main.py
46-
```
47-
48-
Then the project can be run with:
49-
50-
```
51-
pip install -r requirements.txt
52-
```
53-
54-
![Project SS](https://github.com/mcagriaksoy/Serial-Communication-GUI-Program/blob/master/img/Screenshot_v2024_07_2.jpg)
47+
![Project SS](https://github.com/mcagriaksoy/Serial-Communication-GUI-Program/blob/master/img/Screenshot_v2025_04.jpg)
5548

5649
If you encounter any problems while using the COM port tool, try these solutions:
5750

@@ -62,9 +55,9 @@ If you have any questions or feedback, please contact me.
6255

6356
## Dependencies
6457

65-
[![PyQt - >= 6.0](https://img.shields.io/badge/PyQt->_6.0-2ea44f)](https://wiki.python.org/moin/PyQt)
66-
[![PyQt_sip - >= 13.0](https://img.shields.io/badge/PyQt_sip->_13.0-2ea44f)](https://pypi.org/project/PyQt6-sip/)
67-
[![PySerial - >= 3.0](https://img.shields.io/badge/PyQt->_3.0-2ea44f)](https://pypi.org/project/pyserial/)
58+
[![PySide - >= 6.0](https://img.shields.io/badge/PySide->_6.0-2ea44f)](https://wiki.python.org/moin/PySide)
59+
[![PySide_sip - >= 13.0](https://img.shields.io/badge/PySide_sip->_13.0-2ea44f)](https://pypi.org/project/PySide6-sip/)
60+
[![PySerial - >= 3.0](https://img.shields.io/badge/PySide->_3.0-2ea44f)](https://pypi.org/project/pyserial/)
6861

6962
<h2>Documentation</h2>
7063
<div align="center">
@@ -79,6 +72,21 @@ pyinstaller --noconfirm --onefile --windowed --icon "ui/icon.ico" "src/main.py"
7972
8073
```
8174

75+
## Changes
76+
77+
### V1.4.0 - 2025 Update
78+
79+
Feature: Added basic_view_enabled and advanced_view_enabled methods to toggle UI layouts visibility.
80+
Implemented start_loop and stop_loop for managing serial communication with threading.
81+
Added on_save_txt_button_clicked to save received data to a .txt file.
82+
83+
Improvement: Enhanced error handling for serial communication and worker threads.
84+
Added visual feedback for serial port selection and connection status.
85+
86+
Bug Fix: Fixed UI responsiveness during active serial communication.
87+
88+
Refactor: Organized serial communication logic into reusable methods.
89+
8290
</div>
8391
<h2>License</h2>
8492
Released under <a href="/LICENSE">GNU General Public License v3.0</a> by <a href="https://github.com/mcagriaksoy">@mcagriaksoy</a>.

img/Screenshot_v2024_07_2.jpg

-127 KB
Binary file not shown.

img/Screenshot_v2025_04.jpg

52.7 KB
Loading

src/ui_main.py

Lines changed: 73 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66

77
__author__ = 'Mehmet Cagri Aksoy - github.com/mcagriaksoy'
88
__annotations__ = 'AFCOM - Serial Communication GUI Program'
9-
__version__ = '2024.12'
9+
__version__ = '2025 - 1.4.0.0'
1010
__license__ = 'JGPLv3'
11-
__status__ = 'Research'
11+
__status__ = 'Development'
1212

1313
# IMPORTS
1414
from os import path, system
@@ -42,8 +42,20 @@
4242
SERIAL_DEVICE = Serial()
4343
PORTS = []
4444
is_serial_port_established = False
45-
nightModeEnabled = False
46-
simpleViewEnabled = False
45+
46+
from winreg import OpenKey, HKEY_CURRENT_USER, QueryValueEx, ConnectRegistry, KEY_READ, KEY_WOW64_64KEY
47+
48+
def is_windows_dark_mode(self):
49+
try:
50+
registry = ConnectRegistry(None, HKEY_CURRENT_USER)
51+
registry_key = OpenKey(registry, r'Software\Microsoft\Windows\CurrentVersion\Themes\Personalize')
52+
value, _ = QueryValueEx(registry_key, 'AppsUseLightTheme')
53+
return value == 0 # 0 means dark mode is enabled
54+
except WindowsError:
55+
return False
56+
57+
# simpleViewEnabled = False
58+
4759

4860
def get_serial_port():
4961
""" Lists serial port names
@@ -102,6 +114,7 @@ class MainWindow(QMainWindow):
102114
def __init__(self):
103115
""" Initialize Main Window """
104116
super(MainWindow, self).__init__()
117+
105118
if PROGRAM_TYPE_DEBUG:
106119

107120
file_path = path.join("ui/main_window.ui")
@@ -117,6 +130,10 @@ def __init__(self):
117130
print("UI File Found!")
118131
self.ui= Ui_main_window()
119132
self.ui.setupUi(self)
133+
134+
if (is_windows_dark_mode(self)):
135+
print("Windows Dark Mode is enabled!")
136+
# todo add dark mode support for the UI
120137

121138
PORTS = get_serial_port()
122139

@@ -125,7 +142,7 @@ def __init__(self):
125142

126143
self.ui.start_button.clicked.connect(self.start_loop)
127144
self.ui.refresh_button.clicked.connect(self.refresh_port)
128-
145+
'''
129146
self.ui.command_edit_1.clicked.connect(self.command1)
130147
self.ui.command_edit_2.clicked.connect(self.command2)
131148
self.ui.command_edit_3.clicked.connect(self.command3)
@@ -135,49 +152,50 @@ def __init__(self):
135152
self.ui.saved_command_2.clicked.connect(self.move_command2_to_text)
136153
self.ui.saved_command_3.clicked.connect(self.move_command3_to_text)
137154
self.ui.saved_command_4.clicked.connect(self.move_command4_to_text)
155+
'''
138156

139-
self.ui.clear_buffer_button.clicked.connect(self.clear_buffer)
157+
# When actionClear_Cache is triggered, clear the buffer
158+
self.ui.actionClear_Cache.triggered.connect(self.clear_buffer)
140159

141-
self.ui.night_mode.clicked.connect(self.night_mode_clicked)
142-
self.ui.view_change.clicked.connect(self.view_changes)
160+
self.ui.actionBasic_View.triggered.connect(self.basic_view_enabled)
161+
self.ui.actionAdvanced_View.triggered.connect(self.advanced_view_enabled)
162+
#self.ui.clear_buffer_button.clicked.connect(self.clear_buffer)
143163

144-
self.ui.port_comboBox.addItems(PORTS)
164+
# self.ui.view_change.clicked.connect(self.view_changes)
145165

166+
self.ui.port_comboBox.addItems(PORTS)
146167
self.ui.send_button.clicked.connect(self.on_send_data_button_clicked)
147168

148-
self.ui.end_button.clicked.connect(self.on_end_button_clicked)
169+
def basic_view_enabled(self):
170+
""" Hide specific layouts in the UI for basic view """
171+
# Hide all widgets in the verticalLayout_config
172+
for i in range(self.ui.verticalLayout_config.count()):
173+
widget = self.ui.verticalLayout_config.itemAt(i).widget()
174+
if widget:
175+
widget.setVisible(False)
176+
177+
# Optionally, hide all widgets in the formLayout_config
178+
for i in range(self.ui.formLayout_config.count()):
179+
widget = self.ui.formLayout_config.itemAt(i).widget()
180+
if widget:
181+
widget.setVisible(False)
149182

150-
def view_changes(self):
151-
""" Change the window size """
152-
global simpleViewEnabled
153-
# Change the window size
154-
if simpleViewEnabled == False:
155-
self.resize(726, 580)
156-
self.ui.view_change.setText(">>")
157-
simpleViewEnabled = True
158-
else:
159-
self.resize(929, 580)
160-
self.ui.view_change.setText("<<")
161-
simpleViewEnabled = False
162-
163-
def night_mode_clicked(self):
164-
""" Night Mode """
165-
#define static variable
166-
global nightModeEnabled
167-
168-
# Invert all colors
169-
if nightModeEnabled == False:
170-
self.setStyleSheet("background-color: #2C2F33; color: #FFFFFF;")
171-
self.ui.night_mode.setText("🌘 Day Mode")
172-
self.ui.tabWidget.setStyleSheet("QWidget { background-color: #2C2F33; color: #FFFFFF; } QTabBar::tab { background: #2C2F33; color: #FFFFFF; }")
173-
nightModeEnabled = True
174-
else:
175-
self.setStyleSheet("background-color: #FFFFFF; color: #000000;")
176-
self.ui.night_mode.setText("🌘 Night Mode")
177-
self.ui.tabWidget.setStyleSheet("QWidget { background-color: #FFFFFF; color: #000000; } QTabBar::tab { background: #FFFFFF; color: #000000; }")
178-
nightModeEnabled = False
179-
183+
def advanced_view_enabled(self):
184+
""" Show specific layouts in the UI for advanced view """
185+
# Show all widgets in the verticalLayout_config
186+
for i in range(self.ui.verticalLayout_config.count()):
187+
widget = self.ui.verticalLayout_config.itemAt(i).widget()
188+
if widget:
189+
widget.setVisible(True)
190+
191+
# Optionally, show all widgets in the formLayout_config
192+
for i in range(self.ui.formLayout_config.count()):
193+
widget = self.ui.formLayout_config.itemAt(i).widget()
194+
if widget:
195+
widget.setVisible(True)
180196

197+
198+
'''
181199
def command1(self):
182200
""" Open the text input popup to save command for button 1 """
183201
self.command_edit(1)
@@ -228,7 +246,7 @@ def move_command4_to_text(self):
228246
""" Move the saved command to the text box """
229247
self.ui.send_data_text.setText(self.ui.saved_command_4.text())
230248
self.on_send_data_button_clicked()
231-
249+
'''
232250
def refresh_port(self):
233251
""" Refresh the serial port list """
234252
PORTS = get_serial_port()
@@ -318,10 +336,20 @@ def start_loop(self):
318336
return
319337

320338
global is_serial_port_established
339+
340+
if (is_serial_port_established == True):
341+
is_serial_port_established = False
342+
self.on_end_button_clicked()
343+
self.ui.start_button.setText("START")
344+
return
345+
321346
is_serial_port_established = True
347+
# change start_button to stop button
348+
self.ui.start_button.setText("STOP")
349+
322350
try:
323351
self.worker = Worker() # a new worker to perform those tasks
324-
self.thread = QThread() # a new thread to run our background tasks in
352+
self.thread = QThread() # a new thread to run our background tasks in
325353
# move the worker into the thread, do this first before connecting the signals
326354
self.worker.moveToThread(self.thread)
327355
# begin our worker object's loop when the thread starts running
@@ -337,6 +365,8 @@ def start_loop(self):
337365
self.thread.finished.connect(self.thread.deleteLater)
338366
# start the thread
339367
self.thread.start()
368+
369+
340370
except RuntimeError:
341371
self.print_message_on_screen("Exception in Worker Thread!")
342372

@@ -347,12 +377,12 @@ def stop_loop(self):
347377
# Disconnect the serial port and close it
348378
SERIAL_DEVICE.close()
349379

350-
351380
def clear_buffer(self):
352381
""" Clear the buffer """
353382
self.ui.data_textEdit.clear()
354383
self.ui.send_data_text.clear()
355384

385+
356386
def read_data_from_thread(self, serial_data):
357387
""" Write the result to the text edit box"""
358388
# self.ui.data_textEdit.append("{}".format(i))
@@ -423,5 +453,4 @@ def start_ui_design():
423453
""" Start the UI Design """
424454
app = QApplication(argv) # Create an instance
425455
window_object = MainWindow() # Create an instance of our class
426-
window_object.show()
427456
exit(app.exec())

0 commit comments

Comments
 (0)