Создании дизайна чата в PyQt как в стиле телеграмм
Я пытаюсь сделать чат в стиле Telegram используя PyQt5.
Я попробовал пару вариантов создания чего-то похожего на чат и мне кажется, что графика для этого лучше всего подходит.
У меня есть код, но это вряд-ли похоже на чат из телеграмма. Помогите пожалуйста в создании.
main.py:
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, \
QHBoxLayout, QLabel, QTextEdit, QPushButton, QMainWindow, \
QLineEdit, QGraphicsScene, QGraphicsItem, QGraphicsView, \
QGraphicsTextItem, QGraphicsRectItem
from PyQt5.QtCore import Qt
class Window(QMainWindow):
def __init__(self):
super().__init__()
self.initUI() # Инициализирую пользовательский интерфейс
self.current_y = 0 # Переменная для отслеживания текущей высоты
def initUI(self):
self.setWindowTitle("Чат")
self.setGeometry(300, 300, 1200, 700)
central_widget = QWidget(self)
self.setCentralWidget(central_widget)
layout_input_and_send = QHBoxLayout()
layout = QVBoxLayout(central_widget) # создаём вертикальный виджет
layout.addLayout(layout_input_and_send)
# Создаем область графики для чата
self.graphics_view = QGraphicsView(self)
self.graphics_scene = QGraphicsScene(self)
self.graphics_view.setScene(self.graphics_scene)
layout.addWidget(self.graphics_view) # Добавляем QGraphicsView в макет
self.graphics_view.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) # Отключаем горизонтальную прокрутку
# Поле для ввода
self.input_user_command = QLineEdit(self)
self.input_user_command.setPlaceholderText("Введите текст") # Устанавливаем текст подсказку
layout_input_and_send.addWidget(self.input_user_command) # Расположение объекта
# Кнопка отправки сообщения
self.send_button = QPushButton("Отправить", self)
self.send_button.clicked.connect(self.send_message)
layout_input_and_send.addWidget(self.send_button)
def send_message(self):
message = self.input_user_command.text()
if message: # Проверяем, что сообщение не пустое
print("Сообщение: " + message)
text_item = QGraphicsTextItem(message) # Создаем графический элемент текста
# Устанавливаем размеры фона сообщения
rect_width = 350 # Ширина фона
rect_height = text_item.boundingRect().height() + 10 # Высота фона с отступом
# Создаем прямоугольник для фона сообщения
rect_item = QGraphicsRectItem(0, self.current_y, rect_width, rect_height)
rect_item.setBrush(Qt.lightGray) # Устанавливаем цвет фона (светло-серый)
# Устанавливаем позицию текста так, чтобы он был выровнен по правому краю
text_item.setPos(rect_width - text_item.boundingRect().width() - 5, self.current_y + 5) # Отступ 5 пикселей от правого края
# Добавляем прямоугольник и текст в сцену
self.graphics_scene.addItem(rect_item) # Добавляем фон в сцену
self.graphics_scene.addItem(text_item) # Добавляем текст в сцену
# Обновляем текущую высоту для следующего сообщения
self.current_y += rect_height + 10 # Увеличиваем высоту с учетом отступа
self.input_user_command.clear() # Очищаю поле для ввода
self.graphics_view.verticalScrollBar().setValue(self.graphics_view.verticalScrollBar().maximum()) # Прокручиваем вниз, чтобы показать новое сообщение
def keyPressEvent(self, event):
# Проверяем, была ли нажата клавиша Enter
if self.input_user_command.hasFocus() and event.key() == 16777220: # Код клавиши Enter
self.send_message() # Отправляем сообщение
def main():
app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
Ответы (1 шт):
Автор решения: S. Nick
→ Ссылка
Как вариант:
import sys
from random import randrange
from PyQt5 import QtWidgets, QtGui, QtCore
from PyQt5.Qt import *
class WrapLabel(QtWidgets.QTextEdit):
def __init__(self, text=''):
super().__init__(text)
self.setStyleSheet('''
WrapLabel {
border: 1px outset palette(dark);
border-radius: 8px;
background: palette(light);
}
''')
self.setReadOnly(True)
self.setSizePolicy(QtWidgets.QSizePolicy.Preferred,
QtWidgets.QSizePolicy.Maximum)
self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.textChanged.connect(self.updateGeometry)
def minimumSizeHint(self):
doc = self.document().clone()
doc.setTextWidth(self.viewport().width())
height = doc.size().height()
height += self.frameWidth() * 2
return QtCore.QSize(150, height-100)
def sizeHint(self):
return self.minimumSizeHint()
def resizeEvent(self, event):
super().resizeEvent(event)
self.updateGeometry()
class ChatTest(QtWidgets.QScrollArea):
def __init__(self):
super().__init__()
container = QtWidgets.QWidget()
self.setMinimumSize(250, 250)
self.setWidget(container)
self.setWidgetResizable(True)
layout = QtWidgets.QVBoxLayout(container)
layout.addStretch()
self.resize(480, 360)
for i in range(2, 9, 2):
QtCore.QTimer.singleShot(1500 * i, lambda i=i:
self.addMessage(
f'<b>Client:</b> {str(i) * randrange(70, 350)}', i)
)
def addMessage(self, text, i):
wrapLabel = WrapLabel(text)
if i % 2:
wrapLabel.setStyleSheet('''
WrapLabel {
border: 1px outset palette(dark);
border-radius: 8px;
background: palette(light);
margin-left: 50px;
background: #FFFEB7;
}
''')
else:
wrapLabel.setStyleSheet('''
WrapLabel {
border: 1px outset palette(dark);
border-radius: 8px;
background: palette(light);
margin-right: 50px;
background: #C8E6F5;
color: #6D3939;
}
''')
self.widget().layout().addWidget(wrapLabel)
QtCore.QTimer.singleShot(0, self.scrollToBottom)
def scrollToBottom(self):
QtWidgets.QApplication.processEvents()
self.verticalScrollBar().setValue(
self.verticalScrollBar().maximum())
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.central_widget = QWidget(self)
self.setCentralWidget(self.central_widget)
self.chatTest = ChatTest()
self.textEdit = QTextEdit()
self.splitter = QSplitter(self)
self.splitter.setOrientation(Qt.Vertical)
self.splitter.addWidget(self.chatTest)
self.splitter.addWidget(self.textEdit)
self.splitter.setSizes([500, 100])
self.send_button = QPushButton("Отправить")
self.send_button.clicked.connect(self.send_message)
self.h_layout = QHBoxLayout()
self.h_layout.addStretch(1)
self.h_layout.addWidget(self.send_button)
self.v_layout = QVBoxLayout(self.central_widget)
self.v_layout.addWidget(self.splitter)
self.v_layout.addLayout(self.h_layout)
def send_message(self):
message = self.textEdit.toPlainText()
if message:
message = message.replace("\n", "<br>")
self.chatTest.addMessage(message, 1)
self.textEdit.clear()
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.setWindowTitle("Чат")
w.resize(500, 600)
w.show()
sys.exit(app.exec())