After some discussion at work, I couldn't help but dive into Python GUI frameworks just to see what it is like getting started.
I have past experience with Visual C++, Visual Basic, C#, various web frameworks, but haven't done all that much with Python GUIs professionally.
For this evaluation, I'm basically asking ChatGPT to generate some basic single file examples. I may look into recommended file structures, but starting simple for now.
Installation
pip install PyQt6 matplotlib numpy
Example 1 - Hello World
import sys
from PyQt6.QtWidgets import QApplication, QMainWindow
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("PyQt6 Basic Application")
self.setGeometry(100, 100, 600, 400) # x, y, width, height
def main():
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec())
if __name__ == "__main__":
main()
Example 2 - Basic Chart Demo
import sys
import matplotlib
matplotlib.use('QT5Agg') # Use QT5Agg backend for compatibility with PyQt6
from PyQt6.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QWidget, QPushButton, QLabel
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
class MplCanvas(FigureCanvas):
def __init__(self, width=5, height=4, dpi=100):
fig = Figure(figsize=(width, height), dpi=dpi)
self.axes = fig.add_subplot(111)
super().__init__(fig)
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("PyQt6 Application with Buttons, Labels, and Matplotlib Chart")
# Create a central widget
self.central_widget = QWidget()
self.setCentralWidget(self.central_widget)
# Create a vertical layout
self.layout = QVBoxLayout(self.central_widget)
# Add a button
self.button = QPushButton("Click Me")
self.layout.addWidget(self.button)
# Add a label
self.label = QLabel("Hello, PyQt6!")
self.layout.addWidget(self.label)
# Add a Matplotlib chart
self.canvas = MplCanvas(width=5, height=4, dpi=100)
self.canvas.axes.plot([0, 1, 2, 3, 4], [10, 1, 20, 3, 40])
self.layout.addWidget(self.canvas)
# Connect button click to the method
self.button.clicked.connect(self.on_button_clicked)
def on_button_clicked(self):
self.label.setText("Button clicked!")
def main():
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec())
if __name__ == "__main__":
main()
Example 3 - Chart with Controls Demo
This example comprises of dials for setting the frequency and amplitude of a sine wave displayed within a matplotlib chart.
import sys
import numpy as np
from PyQt6.QtWidgets import QApplication, QMainWindow, QWidget, QVBoxLayout, QLabel, QDial
from PyQt6.QtCore import Qt
from PyQt6.QtGui import QFont
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
class SineWavePlotter(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("Sine Wave Plotter")
self.setGeometry(100, 100, 800, 600) # x, y, width, height
# Central Widget and Layout
self.central_widget = QWidget()
self.layout = QVBoxLayout(self.central_widget)
self.setCentralWidget(self.central_widget)
# Matplotlib Figure
self.canvas = FigureCanvas(Figure(figsize=(5, 3)))
self.ax = self.canvas.figure.subplots()
self.layout.addWidget(self.canvas)
# Frequency Dial
self.freqDial = QDial()
self.freqDial.setMinimum(1)
self.freqDial.setMaximum(20)
self.freqDial.setValue(5)
self.freqDial.valueChanged.connect(self.update_plot)
self.layout.addWidget(self.freqDial)
# Amplitude Dial
self.ampDial = QDial()
self.ampDial.setMinimum(1)
self.ampDial.setMaximum(10)
self.ampDial.setValue(1)
self.ampDial.valueChanged.connect(self.update_plot)
self.layout.addWidget(self.ampDial)
# Frequency Label
self.freqLabel = QLabel("Frequency: 5 Hz")
self.freqLabel.setFont(QFont("Arial", 16))
self.freqLabel.setAlignment(Qt.AlignmentFlag.AlignCenter)
self.layout.addWidget(self.freqLabel)
# Amplitude Label
self.ampLabel = QLabel("Amplitude: 1")
self.ampLabel.setFont(QFont("Arial", 16))
self.ampLabel.setAlignment(Qt.AlignmentFlag.AlignCenter)
self.layout.addWidget(self.ampLabel)
# Initial Plot
self.update_plot()
def update_plot(self):
freq = self.freqDial.value()
amp = self.ampDial.value()
self.freqLabel.setText(f"Frequency: {freq} Hz")
self.ampLabel.setText(f"Amplitude: {amp}")
t = np.linspace(0, 1, 1000)
y = amp * np.sin(2 * np.pi * freq * t)
self.ax.clear()
self.ax.plot(t, y)
self.ax.set(xlabel='Time (s)', ylabel='Amplitude',
title='Real-time Sine Wave Plot')
self.canvas.draw()
def main():
app = QApplication(sys.argv)
window = SineWavePlotter()
window.show()
sys.exit(app.exec())
if __name__ == "__main__":
main()
Example 4 - Standard Menus / Toolbar
import sys
from PyQt6.QtWidgets import (QApplication, QMainWindow, QMessageBox, QToolBar, QStyle)
from PyQt6.QtGui import QAction
from PyQt6.QtCore import Qt
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.statusBar().showMessage('Ready')
# Create actions
exitAct = QAction('Exit', self)
exitAct.setShortcut('Ctrl+Q')
exitAct.triggered.connect(QApplication.instance().quit)
aboutAct = QAction('About', self)
aboutAct.triggered.connect(self.about)
# Menu Bar
menubar = self.menuBar()
fileMenu = menubar.addMenu('&File')
fileMenu.addAction(exitAct)
helpMenu = menubar.addMenu('&Help')
helpMenu.addAction(aboutAct)
# Toolbar
toolbar = QToolBar("Main Toolbar")
self.addToolBar(Qt.ToolBarArea.TopToolBarArea, toolbar)
# Create actions with standard icons
action_names = ["New", "Open", "Save", "About"]
tooltips = ["Create something new", "Open a file", "Save the file", "Show the application's About box"]
standard_icons = [QStyle.StandardPixmap.SP_FileIcon, QStyle.StandardPixmap.SP_DirOpenIcon,
QStyle.StandardPixmap.SP_DialogSaveButton, QStyle.StandardPixmap.SP_DialogHelpButton]
for name, tooltip, icon in zip(action_names, tooltips, standard_icons):
action = QAction(self.style().standardIcon(icon), name, self)
action.setToolTip(tooltip)
if name == "About":
action.triggered.connect(self.about)
toolbar.addAction(action)
self.setGeometry(300, 300, 350, 250)
self.setWindowTitle('Main window')
def about(self):
QMessageBox.about(self, "About Application",
"Version 1.0\nThis is a simple PyQt6 application example with a toolbar using standard icons.")
def main():
app = QApplication(sys.argv)
mainWin = MainWindow()
mainWin.show()
sys.exit(app.exec())
if __name__ == '__main__':
main()
Example 5 - Real-Time Chart Demo 2
import sys
import numpy as np
from PyQt6.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QWidget
from PyQt6.QtCore import QTimer
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
class RealTimePlotter(QMainWindow):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
# Set the window title and size
self.setWindowTitle("Real-Time Signal Plotter")
self.setGeometry(100, 100, 800, 600)
# Create a central widget and set layout
central_widget = QWidget()
self.setCentralWidget(central_widget)
layout = QVBoxLayout(central_widget)
# Create a matplotlib figure for plotting the signals
self.figure = Figure()
self.canvas = FigureCanvas(self.figure)
layout.addWidget(self.canvas)
self.ax = self.figure.add_subplot(111)
# Initialize data storage for voltage, current, and power
self.time_window = 30 # seconds
self.update_interval = 500 # milliseconds
self.time_data = np.linspace(-self.time_window, 0, num=int(self.time_window*1000/self.update_interval))
self.voltage_data = np.zeros_like(self.time_data)
self.current_data = np.zeros_like(self.time_data)
self.power_data = np.zeros_like(self.time_data)
# Set up the plot
self.ax.set_xlim(-self.time_window, 0)
self.ax.set_ylim(-10, 10)
self.voltage_line, = self.ax.plot(self.time_data, self.voltage_data, label="Voltage (V)")
self.current_line, = self.ax.plot(self.time_data, self.current_data, label="Current (A)")
self.power_line, = self.ax.plot(self.time_data, self.power_data, label="Power (W)")
self.ax.legend(loc="upper left")
self.ax.set_xlabel("Time (s)")
self.ax.set_ylabel("Signal")
# Set up a timer to update the plot
self.timer = QTimer()
self.timer.setInterval(self.update_interval)
self.timer.timeout.connect(self.update_plot)
self.timer.start()
def update_plot(self):
# Generate pseudo-random data for voltage, current, and power
self.voltage_data = np.roll(self.voltage_data, -1)
self.current_data = np.roll(self.current_data, -1)
self.power_data = np.roll(self.power_data, -1)
self.voltage_data[-1] = np.sin(np.pi * np.random.rand()) * 8
self.current_data[-1] = np.cos(np.pi * np.random.rand()) * 5
self.power_data[-1] = self.voltage_data[-1] * self.current_data[-1] * 0.1 # Simplified calculation
# Update the plot lines
self.voltage_line.set_ydata(self.voltage_data)
self.current_line.set_ydata(self.current_data)
self.power_line.set_ydata(self.power_data)
# Redraw the canvas
self.canvas.draw()
def main():
app = QApplication(sys.argv)
main_window = RealTimePlotter()
main_window.show()
sys.exit(app.exec())
if __name__ == "__main__":
main()
Example 6 - Utilization Monitor
You'll need to install psutil for this one. pip install psutil
import sys
import numpy as np
import psutil
from PyQt6.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QWidget, QLabel
from PyQt6.QtCore import QTimer
from PyQt6.QtGui import QFont
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
class SystemMonitor(QMainWindow):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setWindowTitle("System Performance Monitor")
self.setGeometry(100, 100, 800, 600)
# Create central widget and layout
central_widget = QWidget()
self.setCentralWidget(central_widget)
layout = QVBoxLayout(central_widget)
# Labels for instantaneous and average values
self.cpu_label = QLabel("CPU: 0%")
self.mem_label = QLabel("Memory: 0%")
self.avg_cpu_label = QLabel("Average CPU: 0%")
self.avg_mem_label = QLabel("Average Memory: 0%")
# Set large font for labels
font = QFont("Arial", 16)
self.cpu_label.setFont(font)
self.mem_label.setFont(font)
self.avg_cpu_label.setFont(font)
self.avg_mem_label.setFont(font)
# Add labels to layout
layout.addWidget(self.cpu_label)
layout.addWidget(self.mem_label)
layout.addWidget(self.avg_cpu_label)
layout.addWidget(self.avg_mem_label)
# Matplotlib Figure for plotting
self.figure = Figure()
self.canvas = FigureCanvas(self.figure)
layout.addWidget(self.canvas)
self.ax = self.figure.add_subplot(111)
# Data storage
self.time_window = 20 # seconds
self.update_interval = 1000 # milliseconds
self.time_data = np.linspace(-self.time_window, 0, num=int(self.time_window * 1000 / self.update_interval))
self.cpu_data = np.zeros_like(self.time_data)
self.mem_data = np.zeros_like(self.time_data)
# Set up plot
self.cpu_line, = self.ax.plot(self.time_data, self.cpu_data, label="CPU (%)")
self.mem_line, = self.ax.plot(self.time_data, self.mem_data, label="Memory (%)")
self.ax.legend(loc="upper left")
self.ax.set_ylim(0, 100)
self.ax.set_title("CPU and Memory Utilization")
self.ax.set_xlabel("Time (s)")
self.ax.set_ylabel("Utilization (%)")
# Timer to update data
self.timer = QTimer()
self.timer.setInterval(self.update_interval)
self.timer.timeout.connect(self.update_data)
self.timer.start()
def update_data(self):
# Fetch new data
cpu = psutil.cpu_percent()
mem = psutil.virtual_memory().percent
# Update data arrays
self.cpu_data = np.roll(self.cpu_data, -1)
self.mem_data = np.roll(self.mem_data, -1)
self.cpu_data[-1] = cpu
self.mem_data[-1] = mem
# Update plot lines
self.cpu_line.set_ydata(self.cpu_data)
self.mem_line.set_ydata(self.mem_data)
# Update labels
self.cpu_label.setText(f"CPU: {cpu}%")
self.mem_label.setText(f"Memory: {mem}%")
self.avg_cpu_label.setText(f"Average CPU: {np.mean(self.cpu_data):.2f}%")
self.avg_mem_label.setText(f"Average Memory: {np.mean(self.mem_data):.2f}%")
# Redraw the canvas
self.canvas.draw()
def main():
app = QApplication(sys.argv)
ex = SystemMonitor()
ex.show()
sys.exit(app.exec())
if __name__ == "__main__":
main()
Conclusion
Overall, a positive experience.
Most simple examples generated by ChatGPT worked out of the box with minimal dependencies
Unsure how well it scales for more comprehensive applications.
Resources
Source: https://github.com/ericjameszimmerman/pyqt6-examples