Динамическое отображение данных в PyQt
С помощью библиотеки Pybit я получаю данные криптовалют в реальном времени. Решил усложнить себе задачу и создать для удобства интерфейс на PyQt6, но столкнулся с проблемой.
При запуске программы я получаю одновременно информацию по двум объектам из списка в одном окне. Эта информация динамически изменяется, показывая то один объект то другой (См. Рис. 1, Рис. 2).
Как добавить полученную информацию c новой строки по каждому объекту списка, взависимости от их колличества?
Я ожидаю при запуске программы такую картину: (См.Рис.3)
Вот код интерфейса:
from PyQt6 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(1500,200)
MainWindow.setStyleSheet("background-color: #282828")
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.gridLayout = QtWidgets.QGridLayout(self.centralwidget)
self.search = QtWidgets.QLineEdit(self.centralwidget)
font = QtGui.QFont()
font.setFamily("Times New Roman")
font.setPointSize(32)
self.search.setFont(font)
self.search.setToolTipDuration(-3)
self.search.setStyleSheet("background-color: #161a1e; color: white; border: 3px solid #161a1e")
self.search.setObjectName("search")
self.gridLayout.addWidget(self.search, 0, 0, 1, 4)
self.pushButton = QtWidgets.QPushButton(self.centralwidget)
font = QtGui.QFont()
font.setFamily("Times New Roman")
font.setPointSize(32)
self.pushButton.setFont(font)
self.pushButton.setStyleSheet("background-color: #161a1e; color: white;")
self.pushButton.setObjectName("pushButton")
self.gridLayout.addWidget(self.pushButton, 0, 4, 1, 1)
self.line_1 = QtWidgets.QFrame(self.centralwidget)
self.line_1.setStyleSheet("")
self.line_1.setObjectName("line_1")
self.line_1.setFrameShape(QtWidgets.QFrame.Shape.HLine)
self.line_1.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken)
self.gridLayout.addWidget(self.line_1, 1, 0, 1, 5)
self.marketLabel_1 = QtWidgets.QLabel(self.centralwidget)
font = QtGui.QFont()
font.setFamily("Times New Roman")
font.setPointSize(24)
self.marketLabel_1.setFont(font)
self.marketLabel_1.setStyleSheet("color: white")
self.marketLabel_1.setFixedHeight(40)
self.marketLabel_1.setObjectName("marketLabel_1")
self.gridLayout.addWidget(self.marketLabel_1, 2, 0, 1, 1)
self.marketLabel_2 = QtWidgets.QLabel(self.centralwidget)
font = QtGui.QFont()
font.setFamily("Times New Roman")
font.setPointSize(24)
self.marketLabel_2.setFont(font)
self.marketLabel_2.setStyleSheet("color: white")
self.marketLabel_2.setFixedHeight(40)
self.marketLabel_2.setObjectName("marketLabel_2")
self.gridLayout.addWidget(self.marketLabel_2, 2, 1, 1, 1)
self.marketLabel_3 = QtWidgets.QLabel(self.centralwidget)
font = QtGui.QFont()
font.setFamily("Times New Roman")
font.setPointSize(24)
self.marketLabel_3.setFont(font)
self.marketLabel_3.setStyleSheet("color: white")
self.marketLabel_3.setFixedHeight(40)
self.marketLabel_3.setObjectName("marketLabel_3")
self.gridLayout.addWidget(self.marketLabel_3, 2, 2, 1, 1)
self.marketLabel_4 = QtWidgets.QLabel(self.centralwidget)
font = QtGui.QFont()
font.setFamily("Times New Roman")
font.setPointSize(24)
self.marketLabel_4.setFont(font)
self.marketLabel_4.setStyleSheet("color: white")
self.marketLabel_4.setFixedHeight(40)
self.marketLabel_4.setObjectName("marketLabel_4")
self.gridLayout.addWidget(self.marketLabel_4, 2, 3, 1, 1)
self.line_2 = QtWidgets.QFrame(self.centralwidget)
self.line_2.setStyleSheet("")
self.line_2.setObjectName("line_2")
self.line_2.setFrameShape(QtWidgets.QFrame.Shape.HLine)
self.line_2.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken)
self.gridLayout.addWidget(self.line_2, 3, 0, 1, 5)
self.tradingPairs = QtWidgets.QLabel(self.centralwidget)
font = QtGui.QFont()
font.setFamily("Times New Roman")
font.setPointSize(26)
self.tradingPairs.setFont(font)
self.tradingPairs.setStyleSheet("color: white;")
self.tradingPairs.setFixedHeight(40)
self.tradingPairs.setObjectName("tradingPairs")
self.gridLayout.addWidget(self.tradingPairs, 4, 0, 1, 1)
self.lastTradedPrice = QtWidgets.QLabel(self.centralwidget)
font = QtGui.QFont()
font.setFamily("Times New Roman")
font.setPointSize(26)
self.lastTradedPrice.setFont(font)
self.lastTradedPrice.setStyleSheet("color: white;")
self.lastTradedPrice.setObjectName("lastTradedPrice")
self.gridLayout.addWidget(self.lastTradedPrice, 4, 1, 1, 1)
self.percentageChange = QtWidgets.QLabel(self.centralwidget)
font = QtGui.QFont()
font.setFamily("Times New Roman")
font.setPointSize(26)
self.percentageChange.setFont(font)
self.percentageChange.setStyleSheet("color: white;")
self.percentageChange.setObjectName("percentageChange")
self.gridLayout.addWidget(self.percentageChange, 4, 2, 1, 1)
self.turnover = QtWidgets.QLabel(self.centralwidget)
font = QtGui.QFont()
font.setFamily("Times New Roman")
font.setPointSize(26)
self.turnover.setFont(font)
self.turnover.setStyleSheet("color: white;")
self.turnover.setObjectName("turnover")
self.gridLayout.addWidget(self.turnover, 4, 3, 1, 1)
self.line_3 = QtWidgets.QFrame(self.centralwidget)
self.line_3.setStyleSheet("")
self.line_3.setObjectName("line_3")
self.line_3.setFrameShape(QtWidgets.QFrame.Shape.HLine)
self.line_3.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken)
self.gridLayout.addWidget(self.line_3, 1000, 0, 1, 4)
Вот программы:
import sys
import time
from datetime import datetime
from plyer import notification
from pybit import usdt_perpetual
from PyQt6 import QtCore, QtGui, QtWidgets
from programWindow import Ui_MainWindow
class HandleMessage(QtWidgets.QMainWindow):
def __init__(self, *args, **kwds):
super(HandleMessage, self).__init__()
self.programWindow = Ui_MainWindow()
self.programWindow.setupUi(self)
self.display()
self.connect()
self.addNewLine()
def display(self):
self.programWindow.search.setPlaceholderText('Пример: btc, eth, doge')
self.programWindow.pushButton.clicked.connect(self.addNewLine)
#Подключение
def connect(self):
symbol_list = ["BTCUSDT", "DOGEUSDT"]
ws_linear = usdt_perpetual.WebSocket(
test=False,
ping_interval=3000,
ping_timeout=2000,
domain="bybit"
)
ws_linear.kline_stream(
callback=self.handleMessage,
symbol=symbol_list,
interval="1"
)
#Получение книги заказов
def handleMessage(self, message):
data = message['data'][0]
open = data["open"]
symbol = message["topic"][9:]
close = data['close']
turnover = '{0:,}'.format(int(float(data['turnover']))).replace(',', '.')
priceChange = round((close/open-1)*100, 2)
self.programWindow.lastTradedPrice.setText(str(close))
self.programWindow.tradingPairs.setText(symbol)
self.programWindow.percentageChange.setText(str(priceChange))
self.programWindow.turnover.setText(str(turnover))
if close > open:
self.programWindow.lastTradedPrice.setStyleSheet("color: yellow;\nborder: 0")
self.programWindow.percentageChange.setStyleSheet("color: yellow;\nborder: 0")
elif close < open:
self.programWindow.lastTradedPrice.setStyleSheet("color: red;\nborder: 0")
self.programWindow.percentageChange.setStyleSheet("color: red;\nborder: 0")
else:
self.programWindow.lastTradedPrice.setStyleSheet("color: white;\nborder: 0")
self.programWindow.percentageChange.setStyleSheet("color: white;\nborder: 0")
# Создание новых виджетов (QLineEdit) при нажатии на кнопуку pushButton
def addNewLine(self):
self.tradingPairs = QtWidgets.QLineEdit(self.programWindow.centralwidget)
font = QtGui.QFont()
font.setFamily("Times New Roman")
font.setPointSize(26)
self.tradingPairs.setFont(font)
self.tradingPairs.setStyleSheet("color: white;")
self.tradingPairs.setFixedHeight(40)
self.tradingPairs.setObjectName("tradingPairs")
self.lastTradedPrice = QtWidgets.QLineEdit(self.programWindow.centralwidget)
font = QtGui.QFont()
font.setFamily("Times New Roman")
font.setPointSize(26)
self.lastTradedPrice.setFont(font)
self.lastTradedPrice.setStyleSheet("color: white;")
self.lastTradedPrice.setObjectName("lastTradedPrice")
self.percentageChange = QtWidgets.QLineEdit(self.programWindow.centralwidget)
font = QtGui.QFont()
font.setFamily("Times New Roman")
font.setPointSize(26)
self.percentageChange.setFont(font)
self.percentageChange.setStyleSheet("color: white;")
self.percentageChange.setObjectName("percentageChange")
self.turnover = QtWidgets.QLineEdit(self.programWindow.centralwidget)
font = QtGui.QFont()
font.setFamily("Times New Roman")
font.setPointSize(26)
self.turnover.setFont(font)
self.turnover.setStyleSheet("color: white;")
self.turnover.setObjectName("turnover")
row = self.programWindow.gridLayout.count()-8
self.programWindow.gridLayout.addWidget(self.tradingPairs, row, 0, 1, 1)
self.programWindow.gridLayout.addWidget(self.lastTradedPrice, row, 1, 1, 1)
self.programWindow.gridLayout.addWidget(self.percentageChange, row, 2, 1, 1)
self.programWindow.gridLayout.addWidget(self.turnover, row, 3, 1, 1)
app = QtWidgets.QApplication([])
application = HandleMessage()
application.show()
sys.exit(app.exec())
Я много что уже испробовал, половину не помню уже, но самое близкое к желаемому результату было изменение кода в функции handleMessage, убрав обращение к родительскому классу через .programWindow.
Но в итоге происодит добавление одновременно информации по двум объектам из списка в каждый вновь созданный виджет при помощи функции addNewLine, при этом динамически меняется только в новь созданном виджете! (См. Рис.4)
Код функции:
def handleMessage(self, message):
data = message['data'][0]
open = data["open"]
symbol = message["topic"][9:]
close = data['close']
turnover = '{0:,}'.format(int(float(data['turnover']))).replace(',', '.')
priceChange = round((close/open-1)*100, 2)
#Изменения этого участка кода
self.programWindow.lastTradedPrice.setText(str(close))
self.programWindow.tradingPairs.setText(symbol)
self.programWindow.percentageChange.setText(str(priceChange))
self.programWindow.turnover.setText(str(turnover))
########################################################
if close > open:
self.programWindow.lastTradedPrice.setStyleSheet("color: yellow;\nborder: 0")
self.programWindow.percentageChange.setStyleSheet("color: yellow;\nborder: 0")
elif close < open:
self.programWindow.lastTradedPrice.setStyleSheet("color: red;\nborder: 0")
self.programWindow.percentageChange.setStyleSheet("color: red;\nborder: 0")
else:
self.programWindow.lastTradedPrice.setStyleSheet("color: white;\nborder: 0")
self.programWindow.percentageChange.setStyleSheet("color: white;\nborder: 0")
Ответы (1 шт):
Я не могу проверить ваше приложение.
Я попробовал что-то сделать для вас, имитируя какие-то случайные данные.
Обратите внимание:
- я убрал некоторые виджеты, которые мне не понятны;
- я заменил ваши
QLabelынаQTableViewс модельюQStandardItemModel; - данные криптовалют вы получаете в дополнительном потоке;
- с колонку 'Изменения, %' посчитаете сами, если вы ее не получаете готовую.
import sys
import random
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.Qt import *
class Thread(QThread):
updateSignal = QtCore.pyqtSignal(object)
def __init__(self, symbol_list):
super().__init__()
self.symbol_list = symbol_list
def run(self):
self.msleep(1000)
while True:
# !!!
# !!! тут вы получаю данные криптовалют в реальном времени
# !!!
symbol_ = random.choice(self.symbol_list)
price = round(random.uniform(0.1, 77777.99), 2)
amount = round(random.uniform(0.1, 77777.99), 3)
# !!!
# !!! и передаете в основной поток для отображения
# !!!
result = [symbol_, price, amount]
self.updateSignal.emit(result) # ---->
self.msleep(1000 * 2) # пауза 2sec между запросами на получение новых данных
class HandleMessage(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.centralwidget = QtWidgets.QWidget()
self.centralwidget.setObjectName("centralwidget")
self.setCentralWidget(self.centralwidget)
self.row = 2
self.column = 4
self.symbol_list = ["BTCUSDT", "DOGEUSDT"]
self.thread = None
self.view = QTableView(self)
self.view.setSelectionBehavior(QTableWidget.SelectRows)
self.view.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
self.view.verticalHeader().setSectionResizeMode(QHeaderView.Stretch)
self.header = ['Торговая пара', 'Цена', 'Изменения, %', 'Объем']
self.model = QStandardItemModel(self.row, self.column)
self.model.setHorizontalHeaderLabels(self.header)
self.view.setModel(self.model)
for row in range(self.model.rowCount()):
item = QStandardItem(self.symbol_list[row])
item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
self.model.setItem(row, 0, item)
self.pushButton = QtWidgets.QPushButton('Start', self.centralwidget)
self.pushButton.clicked.connect(self.run_th)
self.pushButton.setObjectName("pushButton")
self.gridLayout = QtWidgets.QGridLayout(self.centralwidget)
self.gridLayout.addWidget(self.view, 0, 0, 1, 4)
self.gridLayout.addWidget(self.pushButton, 1, 3, 1, 1)
def run_th(self):
pass
if self.thread is None:
self.thread = Thread(self.symbol_list)
self.thread.updateSignal.connect(self.update_thread)
self.thread.start()
self.pushButton.setText("Stop")
else:
reply = QMessageBox.question(
self,
'ВНИМАНИЕ !',
"Вы уверены, что хотите прервать обновление данных?",
QMessageBox.Yes, QMessageBox.No
)
if reply == QMessageBox.Yes:
self.thread.terminate()
self.thread = None
self.pushButton.setText("Start")
def update_thread(self, obj): # <----
#print(f'\nobj = {obj}') #
find = self.model.findItems(obj[0])
if not self.model.findItems(obj[0]):
msg = QMessageBoxQMessageBox.information(self,
'Внимание', 'Что-то пошло не так.')
return
rows = self.model.rowCount()
for row in range(rows):
item = self.model.item(row, 0)
if item.text() == obj[0]:
item = QStandardItem(f'{obj[1]:>15.5f}')
self.model.setItem(row, 1, item)
item = QStandardItem(f'{obj[2]:>15.3f}')
self.model.setItem(row, 3, item)
break
self.model.sort(3, Qt.AscendingOrder)
def closeEvent(self, event):
reply = QMessageBox.question(
self,
'Информация',
"Вы уверены, что хотите закрыть приложение?",
QMessageBox.Yes, QMessageBox.No
)
if reply == QMessageBox.Yes:
if self.thread:
self.thread.quit()
del self.thread
super(HandleMessage, self).closeEvent(event)
else:
event.ignore()
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
app.setFont(QtGui.QFont("Consolas", 18, QtGui.QFont.Bold))
w = HandleMessage()
w.resize(1200, 235)
w.show()
sys.exit(app.exec())





