Python PyQtGraphにテキスト/ボタン/コンボボックス/テキストボックス/チェックボックス/線/ラジオボタンを実装する方法を説明する。QLabel/QPushButton/QComboBox/QLineEdit/QCheckBox/QFrame/QRadioButtonを使用する。
完成イメージ
骨子
QLabel/QPushButton/QComboBox/QLineEdit/QCheckBox/QFrame/QRadioButtonのクラスを準備しグラフ内で各クラスのインスタンスを使う。
#!/usr/bin/env python3
from PyQt6.QtWidgets import (QApplication, QWidget, QGraphicsProxyWidget,
QLabel, QPushButton, QComboBox, QLineEdit,
QCheckBox, QFrame, QRadioButton, QButtonGroup)
from PyQt6 import QtGui, QtCore
import pyqtgraph as pg
import sys
class GuiWindow(QWidget):
# 中略
self.graph = pg.GraphicsLayoutWidget(show=True)
ここでQLabel/QPushButton/QComboBox/QLineEdit
/QCheckBox/QFrame/QRadioButtonのクラスのインスタンスを使う
class QLabelのクラス(QWidget):
ここにQlabelのオブジェクトを記述
class QPushButtonのクラス(QWidget):
ここにQPushButtonのオブジェクトを記述
class QComboBoxのクラス(QWidget):
ここにQComboBoxのオブジェクトを記述
class QLineEditのクラス(QWidget):
ここにQLineEditのオブジェクトを記述
class QCheckBoxのクラス(QWidget):
ここにQCheckBoxのオブジェクトを記述
class QFrameのクラス(QWidget):
ここにQFrameのオブジェクトを記述
class QRadioButtonのクラス(QWidget):
ここにQRadioButtonのオブジェクトを記述
if __name__ == '__main__':
qapp = QApplication(sys.argv)
window = GuiWindow()
sys.exit(qapp.exec())
具体例
#!/usr/bin/env python3
from PyQt6.QtWidgets import (QApplication, QWidget, QGraphicsProxyWidget,
QLabel, QPushButton, QComboBox, QLineEdit,
QCheckBox, QFrame, QRadioButton, QButtonGroup)
from PyQt6 import QtGui, QtCore
import pyqtgraph as pg
import sys
import numpy as np
class GuiWindow(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.set_variables()
self.set_objects()
self.set_data()
self.plot_data()
self.set_appearance()
def set_variables(self):
self.range_x_min = -1
self.range_x_max = 5
self.pen_color = (255,255,0)
self.pen_width = 10
self.pen = pg.mkPen(self.pen_color, width=self.pen_width)
def set_data(self):
self.freq = 0.2 # サイン波の周波数 [Hz]
self.Ts = 0.1 # サンプリング周期 [秒]
self.Ns = 1000 # サンプリング点数 [個]
self.ns = np.arange(0, self.Ns) # サンプル番号
self.x = self.ns * self.Ts # 時間データ
self.y = np.sin(2 * np.pi * self.freq * (self.ns * self.Ts)) # サイン波
def clear_data(self):
self.p.clear()
def plot_data(self):
self.p.plot(x=self.x, y=self.y, pen=self.pen)
def set_appearance(self):
self.p.setLabel('left', '大きさ')
self.p.setLabel('bottom', '時間 [秒]')
self.p.setXRange(self.range_x_min, self.range_x_max)
def set_objects(self):
self.graph = pg.GraphicsLayoutWidget(show=True)
# row0-7
self.p = self.graph.addPlot(row=0, col=0, rowspan=9, colspan=4)
# row0-3
self.multiSelector1 = MultiSelector(app=self, win=self.graph, row=0, col=4, w=100, h=25, text='極太')
self.multiSelector2 = MultiSelector(app=self, win=self.graph, row=1, col=4, w=100, h=25, text='太め')
self.multiSelector3 = MultiSelector(app=self, win=self.graph, row=2, col=4, w=100, h=25, text='普通')
self.multiSelector4 = MultiSelector(app=self, win=self.graph, row=3, col=4, w=100, h=25, text='細め')
self.group = QButtonGroup()
self.group.addButton(self.multiSelector4.object)
self.group.addButton(self.multiSelector3.object)
self.group.addButton(self.multiSelector1.object)
self.group.addButton(self.multiSelector2.object)
# row4
self.lineSeparator1 = LineSeparator(app=self, win=self.graph, row=4, col=4, w=100, h=1)
# row6
self.lineSeparator2 = LineSeparator(app=self, win=self.graph, row=6, col=4, w=100, h=1)
# row7
self.touchPadPanel1 = TouchPadPanel(app=self, win=self.graph, row=7, col=4, w=100, h=25, text='CSV化')
# row5(row6,7より前面に出したいので後に作成)
self.pullDownPanel1 = PullDownPanel(app=self, win=self.graph, row=5, col=4, w=100, h=25)
self.pullDownPanel1.object.addItem(" 黃")
self.pullDownPanel1.object.addItem(" 青")
self.pullDownPanel1.object.addItem(" 赤")
# row8
self.flexibleSpace1 = FlexibleSpace(app=self, win=self.graph, row=8, col=4, w=100)
# row9
self.letterDisplay1 = LetterDisplay(app=self, win=self.graph, row=9, col=0, w=50, h=25, text='x max')
self.textEditFrame1 = TextEditFrame(app=self, win=self.graph, row=9, col=1, w=100, h=25, name='x_max', text=str(self.range_x_max))
self.checkReceiver1 = CheckReceiver(app=self, win=self.graph, row=9, col=2, w=100, h=25, text='固定', name='x_max固定')
self.flexibleSpace2 = FlexibleSpace(app=self, win=self.graph, row=9, col=3, h=25)
# row10
self.letterDisplay2 = LetterDisplay(app=self, win=self.graph, row=10, col=0, w=50, h=25, text='x min')
self.textEditFrame2 = TextEditFrame(app=self, win=self.graph, row=10, col=1, w=100, h=25, name='x_min', text=str(self.range_x_min))
self.checkReceiver2 = CheckReceiver(app=self, win=self.graph, row=10, col=2, w=100, h=25, text='固定', name='x_min固定')
self.flexibleSpace3 = FlexibleSpace(app=self, win=self.graph, row=10, col=3, h=25)
class FlexibleSpace(QWidget):
def __init__(self, app, win, row, col, rowspan=1, colspan=1, w=0, h=0, name='', text=''):
super().__init__()
self.set_layout(win=win, row=row, col=col, rowspan=rowspan, colspan=colspan)
self.set_object(app=app, w=w, h=h, name=name, text=text)
self.set_proxy()
self.setInnerText(text=text)
def set_layout(self, win, row, col, rowspan, colspan):
self.p = win.addLayout(row=row, col=col, rowspan=rowspan, colspan=colspan)
self.p.setContentsMargins(10,0,10,0) # 左,上,右,下
def set_object(self, app, w, h, name, text):
def make_object():
self.object = QLabel()
def set_style():
style = ('QLabel{'
'background-color: rgba(0,0,0,0);'
'color: darkgray;'
'}')
self.object.setStyleSheet(style)
def set_size(w, h):
def set_wsize(w):
self.object.setMinimumWidth(w)
self.object.setMaximumWidth(w)
def set_hsize(h):
self.object.setMinimumHeight(h)
self.object.setMaximumHeight(h)
if w > 0:
set_wsize(w)
else:
pass # free size
if h > 0:
set_hsize(h)
else:
pass # free size
make_object()
set_style()
set_size(w=w, h=h)
def set_proxy(self):
self.proxy = QGraphicsProxyWidget()
self.item = self.p.addItem(self.proxy)
self.proxy.setWidget(self.object)
def setInnerText(self, text):
self.object.setText(text)
class LetterDisplay(QWidget):
def __init__(self, app, win, row, col, rowspan=1, colspan=1, w=0, h=0, name='', text=''):
super().__init__()
self.set_layout(win=win, row=row, col=col, rowspan=rowspan, colspan=colspan)
self.set_object(app=app, w=w, h=h, name=name, text=text)
self.set_proxy()
self.setInnerText(text=text)
def set_layout(self, win, row, col, rowspan, colspan):
self.p = win.addLayout(row=row, col=col, rowspan=rowspan, colspan=colspan)
self.p.setContentsMargins(10,0,10,0) # 左,上,右,下
def set_object(self, app, w, h, name, text):
def make_object():
self.object = QPushButton()
def set_style():
style = ('QPushButton{'
'background-color: rgba(0,0,0,0);'
'color: darkgray;'
'text-align: left;'
'}')
self.object.setStyleSheet(style)
def set_size(w, h):
def set_wsize(w):
self.object.setMinimumWidth(w)
self.object.setMaximumWidth(w)
def set_hsize(h):
self.object.setMinimumHeight(h)
self.object.setMaximumHeight(h)
if w > 0:
set_wsize(w)
else:
pass # free size
if h > 0:
set_hsize(h)
else:
pass # free size
def connect_signal_slot():
self.object.clicked.connect(clicked)
def clicked():
print('clicked')
make_object()
set_style()
set_size(w=w, h=h)
connect_signal_slot()
def set_proxy(self):
self.proxy = QGraphicsProxyWidget()
self.item = self.p.addItem(self.proxy)
self.proxy.setWidget(self.object)
def setInnerText(self, text):
self.object.setText(text)
class PullDownPanel(QWidget):
def __init__(self, app, win, row, col, rowspan=1, colspan=1, w=0, h=0, name=''):
super().__init__()
self.set_layout(win=win, row=row, col=col, rowspan=rowspan, colspan=colspan)
self.set_object(app=app, w=w, h=h, name=name)
self.set_proxy()
def set_layout(self, win, row, col, rowspan, colspan):
self.p = win.addLayout(row=row, col=col, rowspan=rowspan, colspan=colspan)
self.p.setContentsMargins(10,0,10,0) # 左,上,右,下
def set_object(self, app, w, h, name):
def make_object():
self.object = QComboBox()
def set_style():
style = ('QComboBox{'
'background-color: rgb(77,77,77);'
'color: rgb(177,177,177);'
'}')
self.object.setStyleSheet(style)
def set_size(w, h):
def set_wsize(w):
self.object.setMinimumWidth(w)
self.object.setMaximumWidth(w)
def set_hsize(h):
self.object.setMinimumHeight(h)
self.object.setMaximumHeight(h)
if w > 0:
set_wsize(w)
else:
pass # free size
if h > 0:
set_hsize(h)
else:
pass # free size
def connect_signal_slot():
self.object.textActivated[str].connect(onActivated)
def onActivated(text):
if text == ' 黃':
app.pen_color = (255,255,0)
if text == ' 青':
app.pen_color = (0,0,255)
if text == ' 赤':
app.pen_color = (255,0,0)
app.pen = pg.mkPen(app.pen_color, width=app.pen_width)
app.clear_data()
app.plot_data()
make_object()
set_style()
set_size(w=w, h=h)
connect_signal_slot()
def set_proxy(self):
self.proxy = QGraphicsProxyWidget()
self.item = self.p.addItem(self.proxy)
self.proxy.setWidget(self.object)
class TextEditFrame(QWidget):
def __init__(self, app, win, row, col, rowspan=1, colspan=1, w=0, h=0, name='', text=''):
super().__init__()
self.set_layout(win=win, row=row, col=col, rowspan=rowspan, colspan=colspan)
self.set_object(app=app, w=w, h=h, name=name, text=text)
self.set_proxy()
self.setInnerText(text=text)
def set_layout(self, win, row, col, rowspan, colspan):
self.p = win.addLayout(row=row, col=col, rowspan=rowspan, colspan=colspan)
self.p.setContentsMargins(10,0,10,0) # 左,上,右,下
def set_object(self, app, w, h, name, text):
def make_object():
self.object = QLineEdit()
def set_style():
style = ('QLineEdit{'
'background-color: rgb(77,77,77);'
'color: white;'
'}')
self.object.setStyleSheet(style)
self.object.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter)
def set_size(w, h):
def set_wsize(w):
self.object.setMinimumWidth(w)
self.object.setMaximumWidth(w)
def set_hsize(h):
self.object.setMinimumHeight(h)
self.object.setMaximumHeight(h)
if w > 0:
set_wsize(w)
else:
pass # free size
if h > 0:
set_hsize(h)
else:
pass # free size
def connect_signal_slot():
self.object.textChanged[str].connect(onChanged)
def onChanged(text):
try:
if name == 'x_max':
app.range_x_max = int(text)
app.p.setXRange(app.range_x_min, app.range_x_max)
elif name == 'x_min':
app.range_x_min = int(text)
app.p.setXRange(app.range_x_min, app.range_x_max)
except:
pass
make_object()
set_style()
set_size(w=w, h=h)
connect_signal_slot()
def set_proxy(self):
self.proxy = QGraphicsProxyWidget()
self.item = self.p.addItem(self.proxy)
self.proxy.setWidget(self.object)
def setInnerText(self, text):
self.object.setText(text)
class CheckReceiver(QWidget):
def __init__(self, app, win, row, col, rowspan=1, colspan=1, w=0, h=0, name='', text=''):
super().__init__()
self.set_layout(win=win, row=row, col=col, rowspan=rowspan, colspan=colspan)
self.set_object(app=app, w=w, h=h, name=name, text=text)
self.set_proxy()
self.setInnerText(text=text)
def set_layout(self, win, row, col, rowspan, colspan):
self.p = win.addLayout(row=row, col=col, rowspan=rowspan, colspan=colspan)
self.p.setContentsMargins(10,0,10,0) # 左,上,右,下
def set_object(self, app, w, h, name, text):
def make_object():
self.object = QCheckBox(text)
def set_style():
style = ('QCheckBox{'
'background-color: rgba(0,0,0,0);'
'color: darkgray;'
'text-align: left;'
'}')
self.object.setStyleSheet(style)
def set_size(w, h):
def set_wsize(w):
self.object.setMinimumWidth(w)
self.object.setMaximumWidth(w)
def set_hsize(h):
self.object.setMinimumHeight(h)
self.object.setMaximumHeight(h)
if w > 0:
set_wsize(w)
else:
pass # free size
if h > 0:
set_hsize(h)
else:
pass # free size
def connect_signal_slot():
self.object.stateChanged.connect(onChanged)
def onChanged():
if self.object.isChecked():
if name == 'x_max固定':
app.textEditFrame1.object.setDisabled(True)
elif name == 'x_min固定':
app.textEditFrame2.object.setDisabled(True)
else:
if name == 'x_max固定':
app.textEditFrame1.object.setDisabled(False)
elif name == 'x_min固定':
app.textEditFrame2.object.setDisabled(False)
make_object()
set_style()
set_size(w=w, h=h)
connect_signal_slot()
def set_proxy(self):
self.proxy = QGraphicsProxyWidget()
self.item = self.p.addItem(self.proxy)
self.proxy.setWidget(self.object)
def setInnerText(self, text):
self.object.setText(text)
class LineSeparator(QWidget):
def __init__(self, app, win, row, col, rowspan=1, colspan=1, w=0, h=0, name=''):
super().__init__()
self.set_layout(win=win, row=row, col=col, rowspan=rowspan, colspan=colspan)
self.set_object(app=app, w=w, h=h, name=name)
self.set_proxy()
def set_layout(self, win, row, col, rowspan, colspan):
self.p = win.addLayout(row=row, col=col, rowspan=rowspan, colspan=colspan)
self.p.setContentsMargins(10,0,10,0) # 左,上,右,下
def set_object(self, app, w, h, name):
def make_object():
self.object = QFrame()
def set_style():
style = ('QFrame{'
'color: rgb(77,77,77);'
'background-color: rgb(77,77,77);'
'}')
self.object.setStyleSheet(style)
self.object.setFrameStyle(QFrame.Shape.Panel | QFrame.Shadow.Plain)
def set_size(w, h):
def set_wsize(w):
self.object.setMinimumWidth(w)
self.object.setMaximumWidth(w)
def set_hsize(h):
self.object.setMinimumHeight(h)
self.object.setMaximumHeight(h)
if w > 0:
set_wsize(w)
else:
pass # free size
if h > 0:
set_hsize(h)
else:
pass # free size
make_object()
set_style()
set_size(w=w, h=h)
def set_proxy(self):
self.proxy = QGraphicsProxyWidget()
self.item = self.p.addItem(self.proxy)
self.proxy.setWidget(self.object)
class TouchPadPanel(QWidget):
def __init__(self, app, win, row, col, rowspan=1, colspan=1, w=0, h=0, name='', text=''):
super().__init__()
self.set_layout(win=win, row=row, col=col, rowspan=rowspan, colspan=colspan)
self.set_object(app=app, w=w, h=h, name=name, text=text)
self.set_proxy()
self.setInnerText(text=text)
def set_layout(self, win, row, col, rowspan, colspan):
self.p = win.addLayout(row=row, col=col, rowspan=rowspan, colspan=colspan)
self.p.setContentsMargins(10,0,10,0) # 左,上,右,下
def set_object(self, app, w, h, name, text):
def make_object():
self.object = QPushButton()
def set_style():
style = ('QPushButton{'
'background-color: rgb(77,77,77);'
'color: rgb(177,177,177);'
'border: none;'
'}'
'QPushButton::hover {'
'background-color: gray;'
'color: black;'
'}')
self.object.setStyleSheet(style)
def set_size(w, h):
def set_wsize(w):
self.object.setMinimumWidth(w)
self.object.setMaximumWidth(w)
def set_hsize(h):
self.object.setMinimumHeight(h)
self.object.setMaximumHeight(h)
if w > 0:
set_wsize(w)
else:
pass # free size
if h > 0:
set_hsize(h)
else:
pass # free size
def connect_signal_slot():
self.object.clicked.connect(clicked)
def clicked(text):
output = np.stack([app.x, app.y]).transpose(1, 0)
np.savetxt('output.csv', output, delimiter=',')
def set_event():
self.app = app
self.object.installEventFilter(self)
make_object()
set_style()
set_size(w=w, h=h)
connect_signal_slot()
set_event()
def set_proxy(self):
self.proxy = QGraphicsProxyWidget()
self.item = self.p.addItem(self.proxy)
self.proxy.setWidget(self.object)
def setInnerText(self, text):
self.object.setText(text)
def eventFilter(self, object, event):
if event.type() == QtCore.QEvent.Type.Enter:
self.app.flexibleSpace1.setInnerText('CSV化する?')
elif event.type() == QtCore.QEvent.Type.Leave:
self.app.flexibleSpace1.setInnerText('')
return False
class MultiSelector(QWidget):
def __init__(self, app, win, row, col, rowspan=1, colspan=1, w=0, h=0, name='', text=''):
super().__init__()
self.set_layout(win=win, row=row, col=col, rowspan=rowspan, colspan=colspan)
self.set_object(app=app, w=w, h=h, name=name, text=text)
self.set_proxy()
self.setInnerText(text=text)
def set_layout(self, win, row, col, rowspan, colspan):
self.p = win.addLayout(row=row, col=col, rowspan=rowspan, colspan=colspan)
self.p.setContentsMargins(10,0,10,0) # 左,上,右,下
def set_object(self, app, w, h, name, text):
def make_object():
self.object = QRadioButton()
def set_style():
style = ('QRadioButton{'
'background-color: rgba(0,0,0,0);'
'color: darkgray;'
'}')
self.object.setStyleSheet(style)
self.object.setChecked(True)
def set_size(w, h):
def set_wsize(w):
self.object.setMinimumWidth(w)
self.object.setMaximumWidth(w)
def set_hsize(h):
self.object.setMinimumHeight(h)
self.object.setMaximumHeight(h)
if w > 0:
set_wsize(w)
else:
pass # free size
if h > 0:
set_hsize(h)
else:
pass # free size
def connect_signal_slot():
self.object.toggled.connect(toggled)
def toggled():
try:
radioBtn = app.graph.sender()
if radioBtn.isChecked():
if radioBtn.text() == '極太':
app.pen_width = 100
if radioBtn.text() == '太め':
app.pen_width = 10
if radioBtn.text() == '普通':
app.pen_width = 5
if radioBtn.text() == '細め':
app.pen_width = 1
app.pen = pg.mkPen(app.pen_color, width=app.pen_width)
app.clear_data()
app.plot_data()
except:
pass
make_object()
set_style()
set_size(w=w, h=h)
connect_signal_slot()
def set_proxy(self):
self.proxy = QGraphicsProxyWidget()
self.item = self.p.addItem(self.proxy)
self.proxy.setWidget(self.object)
def setInnerText(self, text):
self.object.setText(text)
if __name__ == '__main__':
qapp = QApplication(sys.argv)
window = GuiWindow()
sys.exit(qapp.exec())
まとめ
Python PyQtGraphにテキスト/ボタン/コンボボックス/テキストボックス/チェックボックス/線/ラジオボタンを実装する方法を説明した。
コメント