Страницы

Поиск по вопросам

Показаны сообщения с ярлыком pyqt5. Показать все сообщения
Показаны сообщения с ярлыком pyqt5. Показать все сообщения

вторник, 31 марта 2020 г.

Обновление виджета QLabel PyQt5

#python #pyqt5


Здравствуйте. Подскажите как обновить виджет с фотографией - QLabel, библиотеки PyQt5
в python 3.6. Смысл заключается в том, что сокет получает bytes фотографии и нужно
при каждом получении обновлять фотографию в окне gui.

Код gui:

import io
from PIL import Image
from PIL.ImageQt import ImageQt
from PyQt5.QtGui import *
from PyQt5 import QtWidgets, QtGui
import sys


class Window(QtWidgets.QWidget):
    def __init__(self, ):
        super().__init__()
        self.resize(800, 600)
        self.wiget_photo()

    def wiget_photo(self):
        self.img = Image.open(io.BytesIO(photo)) #открытие bytes фото (библиотека PIL)
        self.qimage = ImageQt(self.img)
        self.pixmap = QPixmap.fromImage(self.qimage) #формотирование bytes фото в
pixmap для setPixmap
        self.lbl = QtWidgets.QLabel(self)
        self.pix = QtGui.QPixmap(self.pixmap)
        self.lbl.setPixmap(self.pix)
        self.lbl.resize(500, 500) #размер виджета
        self.lbl.move(50, 50) #расположение виджета
        self.show()

if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    GUI = Window()
    sys.exit(app.exec_())

    


Ответы

Ответ 1



Чтобы показывать картинки, полученные через сокет, можно принимать картинки в фоновом потоке, используя простой сокет сервер (в общем случае, Qt позволяет сервер в цикле событий запустить в том же потоке) и получив картинку послать сигнал, чтобы отобразить картинку в GUI: #!/usr/bin/env python3 import socket import sys from PyQt5.QtCore import QObject, QThread, pyqtSignal from PyQt5.QtGui import QPixmap from PyQt5.QtWidgets import QApplication, QLabel def server(signal_obj, host='localhost', port=29044): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # reuse sockets in TIME_WAIT state sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sock.bind((host, port)) sock.listen() signal_obj.server_started.emit(host, port) while True: conn, addr = sock.accept() # XXX add error handling with conn, conn.makefile('rb') as file: # one client at a time signal_obj.got_image.emit(addr, file.read()) # image received class SignalObject(QObject): server_started = pyqtSignal(str, int) # host, port got_image = pyqtSignal(tuple, bytes) # addr, image data def receive_images(self): server(self) class ImageViewer(QLabel): def on_server_start(self, host, port): self.setText(f'Waiting for images on {host}:{port}') self.adjustSize() def on_received_image(self, addr, image_data): self.setWindowTitle('Image from {}:{}'.format(*addr)) pixmap = QPixmap() pixmap.loadFromData(image_data) self.setPixmap(pixmap) self.resize(pixmap.width(), pixmap.height()) app = QApplication(sys.argv) # run server in a background thread thread = QThread() signal_obj = SignalObject() # communicate with GUI using signals signal_obj.moveToThread(thread) thread.started.connect(signal_obj.receive_images) image_viewer = ImageViewer() image_viewer.setWindowTitle('Show Images from socket') signal_obj.server_started.connect(image_viewer.on_server_start) signal_obj.got_image.connect(image_viewer.on_received_image) image_viewer.show() thread.start() # start server sys.exit(app.exec()) Чтобы послать картинку при запущенном приложении: $ nc localhost 29044 < /path/to/image.png В коде две основных части: server() ожидает по указанному адресу (host, port) новые соединения. Когда клиент подключается, сервер читает данные и публикует их как got_image сигнал: signal_obj.got_image.emit(addr, file.read()) GUI, которое подписано на этот сигнал: signal_obj.got_image.connect(image_viewer.on_received_image) показывает новую картинку, используя Pixmap.loadFromData метод. Отображение картинок на экран PyQt5 доступных как bytes. В Qt у каждого объекта, есть свой поток (thread affinity), чтобы SignalObject.receive_images слот выполнялся в фоновом потоке, используется signal_obj.moveToThread(thread) вызов. Background thread with QThread in PyQt. Не обязательно QThread использовать, посылка сигналов является thread-safe, можно из обычного Питон-потока сигналы посылать, пример кода.

Ответ 2



Пример обновлении QLabel при помощи функции setText() раз в секунду. В вашем случае обновление будет при получении фотографии. import sys from PyQt5 import QtWidgets, QtCore class Main(QtWidgets.QWidget): def __init__(self): super().__init__() self.setFixedSize(200, 200) self.setWindowTitle('Test') self.i = 0 self.label = QtWidgets.QLabel() lay = QtWidgets.QVBoxLayout() lay.addWidget(self.label) self.setLayout(lay) self.timer = QtCore.QTimer() self.timer.timeout.connect(self.tick) self.timer.start(1000) def tick(self): self.i += 1 self.label.setText("Значение равно {}".format(self.i)) if self.i == 10: self.label.setText("Подсчет окончен") self.timer.stop() if __name__ == "__main__": app = QtWidgets.QApplication(sys.argv) main = Main() main.show() sys.exit(app.exec_())

Как внедрить многопоточность в PyQt [дубликат]

#python #python_3x #pyqt5


        
             
                
                    
                        
                            На этот вопрос уже дан ответ здесь:
                            
                        
                    
                
                        
                            оконное приложение начинает “Не отвечать” и замораживается
при передаче больших данных в момент работы интерфейса
                                
                                    (1 ответ)
                                
                        
                                Закрыт 2 года назад.
            
                    
К примеру, есть такой код

import sys
from PyQt5 import QtCore, QtGui, QtWidgets, uic

class MyWin(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        QtWidgets.QWidget.__init__(self, parent)
        self.Menu()
    def Menu(self):
        uic.loadUi("menu.ui", self)
        '''Здесь происходит всякая логика, смена ui и т.д.'''

if __name__=="__main__":
    app = QtWidgets.QApplication(sys.argv)
    w = MyWin()
    w.show()
    sys.exit(app.exec_())


Но в один момент нужно воспользоваться многопоточностью. К примеру, создать секундомер,
который не стопорил бы всю программу. Как это можно реализовать посредством QThread.
P.S. Нужно сделать так, чтобы в потоке можно было использовать переменные класса окна
    


Ответы

Ответ 1



3 разных и простых способа работы с потоками. import sys import traceback from PyQt5.QtCore import (QCoreApplication, QObject, QRunnable, QThread, QThreadPool, pyqtSignal, pyqtSlot) from PyQt5 import Qt # Если при ошибке в слотах приложение просто падает без стека, # есть хороший способ ловить такие ошибки: def log_uncaught_exceptions(ex_cls, ex, tb): text = '{}: {}:\n'.format(ex_cls.__name__, ex) #import traceback text += ''.join(traceback.format_tb(tb)) print(text) Qt.QMessageBox.critical(None, 'Error', text) quit() sys.excepthook = log_uncaught_exceptions class WorkerSignals(QObject): ''' Определяет сигналы, доступные из рабочего рабочего потока Worker(QRunnable).''' finish = pyqtSignal() error = pyqtSignal(tuple) result = pyqtSignal(object) progress = pyqtSignal(int) class Worker(QRunnable): ''' Наследует от QRunnable, настройки рабочего потока обработчика, сигналов и wrap-up. ''' def __init__(self, fn, *args, **kwargs): super(Worker, self).__init__() # Хранить аргументы конструктора (повторно используемые для обработки) self.fn = fn self.args = args self.kwargs = kwargs self.signals = WorkerSignals() print("\nfn=`{}`, \nargs=`{}`, kwargs=`{}`, \nself.signals=`{}`"\ .format(fn, args, kwargs, self.signals)) #== Добавьте обратный вызов в наши kwargs ====================================### kwargs['progress_callback'] = self.signals.progress print("kwargs['progress_callback']->`{}`\n".format(kwargs['progress_callback'])) @pyqtSlot() def run(self): # Получите args/kwargs здесь; и обработка с их использованием try: # выполняем метод `execute_this_fn` переданный из Main result = self.fn(*self.args, **self.kwargs) except: traceback.print_exc() exctype, value = sys.exc_info()[:2] self.signals.error.emit((exctype, value, traceback.format_exc())) else: # если ошибок не была, испускаем сигнал .result и передаем результат `result` self.signals.result.emit(result) # Вернуть результат обработки finally: self.signals.finish.emit() # Done / Готово # Подклассификация QThread # http://qt-project.org/doc/latest/qthread.html class AThread(QThread): threadSignalAThread = pyqtSignal(int) def __init__(self): super().__init__() def run(self): count = 0 while count < 1000: #time.sleep(1) Qt.QThread.msleep(200) count += 1 self.threadSignalAThread.emit(count) # Подкласс QObject и использование moveToThread class SomeObject(QObject): finishedSomeObject = pyqtSignal() threadSignalSomeObject = pyqtSignal(int) def long_running(self): print('SomeObject(QObject) id', int(QThread.currentThreadId())) count = 0 while count < 150: Qt.QThread.msleep(100) count += 1 self.threadSignalSomeObject.emit(count) self.finishedSomeObject.emit() class MsgBoxAThread(Qt.QDialog): """ Класс инициализации окна для визуализации дополнительного потока и кнопка для закрытия потокового окна, если поток остановлен! """ def __init__(self): super().__init__() layout = Qt.QVBoxLayout(self) self.label = Qt.QLabel("") layout.addWidget(self.label) close_btn = Qt.QPushButton("Close Окно") layout.addWidget(close_btn) # ------- Сигнал это только закроет окно, поток как работал, так и работает close_btn.clicked.connect(self.close) self.setGeometry(900, 65, 400, 80) self.setWindowTitle('MsgBox AThread(QThread)') class MsgBoxSomeObject(Qt.QDialog): def __init__(self): super().__init__() layout = Qt.QVBoxLayout(self) self.label = Qt.QLabel("") layout.addWidget(self.label) close_btn = Qt.QPushButton("Close Окно") layout.addWidget(close_btn) # ------- Сигнал это только закроет окно, поток как работал, так и работает close_btn.clicked.connect(self.close) self.setGeometry(900, 185, 400, 80) self.setWindowTitle('MsgBox SomeObject(QObject)') class MsgBoxWorker(Qt.QDialog): def __init__(self): super().__init__() layout = Qt.QVBoxLayout(self) self.label = Qt.QLabel("") layout.addWidget(self.label) close_btn = Qt.QPushButton("Close Окно") layout.addWidget(close_btn) # ------- Сигнал это только закроет окно, поток как работал, так и работает close_btn.clicked.connect(self.close) self.setGeometry(900, 300, 400, 80) self.setWindowTitle('MsgBox Worker(QRunnable)') class ExampleThread(Qt.QWidget): def __init__(self, parent=None): super(ExampleThread, self).__init__(parent) layout = Qt.QVBoxLayout(self) self.lbl = Qt.QLabel("Start") layout.addWidget(self.lbl) self.btnA = Qt.QPushButton("Запустить AThread(QThread)") layout.addWidget(self.btnA) self.btnB = Qt.QPushButton("Запустить SomeObject(QObject)") layout.addWidget(self.btnB) self.btnC = Qt.QPushButton("Запустить Worker(QRunnable)") layout.addWidget(self.btnC) self.progressBar = Qt.QProgressBar() self.progressBar.setProperty("value", 0) layout.addWidget(self.progressBar) self.setGeometry(550, 65, 300, 300) self.setWindowTitle('3 разных и простых способа работы с потоками.') self.btnA.clicked.connect(self.using_q_thread) self.btnB.clicked.connect(self.using_move_to_thread) self.btnC.clicked.connect(self.using_q_runnable) self.msg = MsgBoxAThread() self.thread = None self.msgSomeObject = MsgBoxSomeObject() self.objThread = None self.counter = 0 self.timer = Qt.QTimer() self.timer.setInterval(1000) # -------- timeout -------> def recurring_timer(self): self.timer.timeout.connect(self.recurring_timer) self.timer.start() self.threadpool = QThreadPool() print("Max потоков, кот. будут использоваться=`%d`" % self.threadpool.maxThreadCount()) self.msgWorker = MsgBoxWorker() self.threadtest = QThread(self) self.idealthreadcount = self.threadtest.idealThreadCount() print("Ваша машина может обрабатывать `{}` потокa оптимально.".format(self.idealthreadcount)) def recurring_timer(self): self.counter += 1 self.lbl.setText("СЧЁТЧИК цикл GUI: %d" % self.counter) # ---- AThread(QThread) -----------# def using_q_thread(self): if self.thread is None: self.thread = AThread() self.thread.threadSignalAThread.connect(self.on_threadSignalAThread) self.thread.finished.connect(self.finishedAThread) self.thread.start() self.btnA.setText("Stop AThread(QThread)") else: self.thread.terminate() self.thread = None self.btnA.setText("Start AThread(QThread)") def finishedAThread(self): self.thread = None self.btnA.setText("Start AThread(QThread)") def on_threadSignalAThread(self, value): self.msg.label.setText(str(value)) # Восстанавливаем визуализацию потокового окна, если его закрыли. Поток работает. # .setVisible(true) или .show() устанавливает виджет в видимое состояние, # если видны все его родительские виджеты до окна. if not self.msg.isVisible(): self.msg.show() # --END-- AThread(QThread) -------------------# # ---- SomeObject(QObject) -------------------# def using_move_to_thread(self): if self.objThread is None: self.objThread = QThread() self.obj = SomeObject() self.obj.moveToThread(self.objThread) # Переместить в поток для выполнения self.obj.threadSignalSomeObject.connect(self.on_threadSignalSomeObject) self.obj.finishedSomeObject.connect(self.finishedSomeObject) self.objThread.started.connect(self.obj.long_running) self.objThread.start() self.btnB.setText("Wait SomeObject(QObject)") self.btnB.setEnabled(False) else: pass def finishedSomeObject(self): self.objThread.terminate() self.objThread.wait(1) self.objThread = None self.btnB.setEnabled(True) self.btnB.setText("Start SomeObject(QObject)") def on_threadSignalSomeObject(self, value): self.msgSomeObject.label.setText(str(value)) # Восстанавливаем визуализацию потокового окна, если его закрыли. Поток работает. if not self.msgSomeObject.isVisible(): self.msgSomeObject.show() # --END-- SomeObject(QObject) -------------------# # ---- Worker(QRunnable) ------------------------# def using_q_runnable(self): # Передайте функцию для выполнения # Любые другие аргументы, kwargs передаются функции run worker = Worker(self.execute_this_fn) worker.signals.result.connect(self.print_output) worker.signals.finish.connect(self.thread_complete) worker.signals.progress.connect(self.progress_fn) self.threadpool.start(worker) def progress_fn(self, n): self.progressBar.setValue(n) self.msgWorker.label.setText(str(n)) # Восстанавливаем визуализацию потокового окна, если его закрыли. Поток работает. if not self.msgWorker.isVisible(): self.msgWorker.show() def execute_this_fn(self, progress_callback): for n in range(0, 11): Qt.QThread.msleep(600) progress_callback.emit(n*100/10) return "Готово." def print_output(self, s): print("\ndef print_output(self, s):", s) def thread_complete(self): print("\nTHREAD ЗАВЕРШЕН!, self->", self) # --END-- Worker QRunnable) -------------------# #==============================================### # потоки или процессы должны быть завершены ### def closeEvent(self, event): reply = Qt.QMessageBox.question\ (self, 'Информация', "Вы уверены, что хотите закрыть приложение?", Qt.QMessageBox.Yes, Qt.QMessageBox.No) if reply == Qt.QMessageBox.Yes: if self.thread: self.thread.quit() del self.thread self.msg.close() if self.objThread: self.objThread.setTerminationEnabled(True) self.objThread.terminate() self.objThread.wait(1) self.msgSomeObject.close() # закрыть поток Worker(QRunnable) self.msgWorker.close() super(ExampleThread, self).closeEvent(event) else: event.ignore() if __name__ == '__main__': app = Qt.QApplication([]) mw = ExampleThread() mw.show() app.exec()

Ответ 2



В первую очередь стоит рассмотреть вариант без потоков. К примеру, для реализации секундомера, чтобы отложить выполнение функции по времени, можно рассмотреть методы QTimer класса. Для сетевых соединений, чтобы не использовать блокирующих функций типа requests.get(), можно рассмотреть использование асинхронного интерфейса такого как QNetworkAccessManager. Есть несколько (в том числе уже устаревших) способов использовать потоки в qt5 (QThread, QRunnable, QThreadPool, QConcurrent). Так как большинство GUI методов не являются потокобезопасными, то общение из фонового потока с GUI потоком можно с помощью сигналов организовывать. Пример: Обновление виджета QLabel PyQt5. Не обязательно даже QThread использовать. Сигналы можно посылать из обычных Питон-потоков, пример.

Ответ 3



Вот пример QThread import os import sys from time import sleep from PyQt5.QtWidgets import * from PyQt5.QtCore import * from PyQt5.QtGui import * class SenderMessage(QObject): text_value = pyqtSignal(str) int_value = pyqtSignal(int) def __init__(self): super().__init__() @pyqtSlot() def run(self): self.text_value.emit("Привет!") sleep(1.5) self.text_value.emit("Я PyQt5.") sleep(1.5) self.text_value.emit("Мы сегодня тестируем...") sleep(1.5) self.text_value.emit("Класс QThread.") for i in range(10, 101, 1): sleep(0.1) self.int_value.emit(i) self.text_value.emit("Тест завершён.") sleep(1.5) self.text_value.emit("Приложение будет закрыто.") class Window(QMainWindow): def __init__(self): super().__init__() self.initUI() def initUI(self): try: self.setWindowTitle("Многопоточность") self.setGeometry(400, 200, 350, 80) self.label = QLabel(self) self.label.setGeometry(0, 0, 350, 50) self.label.setStyleSheet("color: rgb(25, 156, 25);\ font: italic 18pt MS Shell Dlg 2; border: 5px solid red;") self.danger = "QProgressBar::chunk {background: QLinearGradient( x1: 0, y1: 0, x2: 1, y2: 0,stop: 0 #FF0350,stop: 0.4999 #00d920,stop: 0.5 #FF0019,stop: 1 #ff0000 );border-bottom-right-radius: 5px;border-bottom- left-radius: 5px;border: .px solid black;}" self.safe = "QProgressBar::chunk {background: QLinearGradient( x1: 0, y1: 0, x2: 1, y2: 0,stop: 0 #78d,stop: 0.4999 #46a,stop: 0.5 #45a,stop: 1 #238 );border-bottom-right-radius: 7px;border-bottom-left- radius: 7px;border: 1px solid black;}" self.progress_bar = QProgressBar(self) self.progress_bar.setStyleSheet(self.safe) self.progress_bar.setValue(10) self.progress_bar.setGeometry(0, 50, 350, 30) self.thread = QThread() self.sender_message = SenderMessage() self.timer = QTimer(self) self.timer.timeout.connect(self.close) self.timer.start(17000) self.sender_message.moveToThread(self.thread) self.sender_message.text_value.connect(self.signalHandlerText) self.sender_message.int_value.connect(self.signalHandlerInt) self.thread.started.connect(self.sender_message.run) self.thread.start() except Exception as exc: print(exc) def signalHandlerText(self, text): self.label.setText(text) def signalHandlerInt(self, value): self.progress_bar.setValue(value) if self.progress_bar.value() < 80: self.progress_bar.setStyleSheet(self.safe) else: self.progress_bar.setStyleSheet(self.danger) if __name__ == '__main__': app = QApplication(sys.argv) window = Window() window.show() sys.exit(app.exec_())

среда, 4 марта 2020 г.

Python PyQt5 убрать кнопку Развернуть/Свернуть

#python #python_3x #pyqt5


Есть окно на PyQt5:

# -*- coding: utf-8 -*-

import sys
from PyQt5.QtWidgets import QApplication, QWidget


class Window(QWidget):
    def __init__(self):
        super().__init__()

        self.initUI()

    def initUI(self):
        self.setFixedSize(200, 350)
        self.setWindowTitle('Test')

        self.show()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    w = Window()
    sys.exit(app.exec_())


Как убрать ненужный пункт меню Развернуть/Свернуть?


    


Ответы

Ответ 1



В Qt для различных виджетов и диалоговых окон можно задавать WindowsFlags, меняющие их отображение. Чтобы сделать что-то нестандартное, нужно объявить наш виджет custom'ным, для этого используется флаг Qt::CustomizeWindowHint, Например, следующий код показывает только кнопку закрытия у диалогового окна в Qt (C++): QDialog d; d.setWindowFlags( Qt::CustomizeWindowHint | Qt::WindowCloseButtonHint ); d.setWindowTitle("abcd"); d.show(); Подробнее: официальный пример работы с флагами Qt перечень Qt::WindowsFlags

Создание нового окна в pyqt5, во время выполнения потока в основном окне

#python #pyqt5


У меня есть два окна.

Основное, которое выполняет некую функцию, используя при этом потоки. В определённый
момент, основное окно вызывает побочное(окно уведомления). Если я не использую потоки,
всё работает в норме, если использую. То окно уведомления появляется на короткий миг,
в который оно не доступно, после чего исчезает(также возможно выставить sleep, чтобы
проверить это).

Вопрос: как организовать вызов второго окна, во время выполнения потоков в первом.

def thread(my_func):
    """
    Run function in a different thread
    """
    def wrapper(*args, **kwargs):
        my_thread = threading.Thread(target=my_func, args=args, kwargs=kwargs)
        my_thread.start()
    return wrapper


# Окно уведомлений
class MsgBox(QWidget):
    def __init__(self):
        super(MsgBox, self).__init__()

        self.setFixedSize(200, 50)
        self.location_on_the_screen()
        self.setWindowTitle('Сообщение')

        self.lbl = QtWidgets.QLabel('', self)
        self.lbl.setOpenExternalLinks(True)
        self.lbl.move(15, 10)
        self.lbl.setText(self.message)

# Основное окно
class Ui_Form(QMainWindow):
    # signal value for thread
    my_signal = QtCore.pyqtSignal(list, name='my_signal')

    def setupUi(self, Form):
        # По клику выполняется метод func
        self.button.clicked.connect(lambda: self.func(self.my_signal))

        # Обработчик сигнала
        self.my_signal.connect(self.mySignalHandler, QtCore.Qt.QueuedConnection)

    # Метод создания окна уведомлений
    def create_window(self):
        second_window = MsgBox()
        second_window.show()

    # Метод основной, выполняется с потоками
    @thread
    def func(self,my_signal):
        .......
        self.create_window()
        ......


# Вызов
if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)

    Form = QMainWindow()
    ui = Ui_Form()
    ui.get_from_config_file()
    ui.setupUi(Form)
    Form.show()

    sys.exit(app.exec_())

    


Ответы

Ответ 1



Пример с потоком, который выводит второе окно, как приходит сообщение из потока. При этом не блокируется ни основное окно, ни дополнительное. from PyQt5 import Qt class WorkThread(Qt.QThread): threadSignal = Qt.pyqtSignal(int) def __init__(self): super().__init__() def run(self, *args, **kwargs): c = 0 while True: Qt.QThread.msleep(1000) c += 1 self.threadSignal.emit(c) return Qt.QThread.run(self, *args, **kwargs) class MsgBox(Qt.QDialog): def __init__(self): super().__init__() layout = Qt.QVBoxLayout(self) self.label = Qt.QLabel("") layout.addWidget(self.label) close_btn = Qt.QPushButton("Close") close_btn.clicked.connect(self.close) layout.addWidget(close_btn) self.resize(50, 50) class MainWindow(Qt.QMainWindow): def __init__(self): super().__init__() self.resize(300, 200) self.btn = Qt.QPushButton("Run thread!") self.btn.clicked.connect(self.on_btn) self.msg = MsgBox() self.setCentralWidget(self.btn) self.thread = None def on_btn(self): if self.thread is None: self.thread = WorkThread() self.thread.threadSignal.connect(self.on_threadSignal) self.thread.start() self.btn.setText("Stop thread") else: self.thread.terminate() self.thread = None self.btn.setText("Start thread") def on_threadSignal(self, value): self.msg.label.setText(str(value)) if not self.msg.isVisible(): self.msg.show() if __name__ == '__main__': app = Qt.QApplication([]) mw = MainWindow() mw.show() app.exec()

Выделение PyQt5 QIcon как ошибка в PyCharm

#python #python_3x #pyqt5 #pycharm


Почему возникает ошибка (выделение что это ошибка) в PyCharm. И как ее исправить.


  Cannot find refence 'QIcon' in 'QtGui.pyd'







UPDATE

Если вместо  from PyQt5 import QtGui вводить from PyQt5.QtGui import * то: 

Если вводить from PyQt5.QtGui import QIcon то:




UPDATE РАЗРЯДНОСТЬ 







Ошибки в Spyder 


    


Ответы

Ответ 1



Данная ошибка, как правило, связанна с тем, что статический анализатор кода настроен на использование описаний к PyQt4 Если данная ошибка влияет на работоспособность программы: можно предположить, что у Вас установлено несколько интерпретаторов питона. Например в системе есть, кроме стандартного, еще анаконда, либо применяли virtualenv. Проверить какой интерпретатор задействован в PyCharm: file -> settings -> project "name" -> project interpreter В консоли (линукс) qmake -v покажет какая версия будет использована по умолчанию. если версии совпадают - попробуйте сменить и вернуть обратно используемый интерпретатор в PyCharm и\или проверить разрядность установленных интерпретаторов и переустановить pyqt(или как раз задействовать virtualenv). Если ошибка не влияет на работоспособность кода, но раздражает: 1) принудительно проинспектировать проект (code - inspect code) и добавить данные ошибки в игнорируемые. 2) настроить pycodestyle (file-settings - "project name" interpreter - найти в списке pycodestyle и дважды по нему кликнуть) на игнорирование такого типа ошибок в принципе, думаю не совсем хорошо в долгосрочной перспективе в Spyder можно просто добавить в начало файла # pylint: disable=missing-docstring # pylint: disable=no-name-in-module # pylint: disable=unused-import

понедельник, 2 марта 2020 г.

Как перемещать приложение, если шапка с кнопками управления окна (закрыть/свернуть/расширить) скрыта

#python #python_3x #pyqt5


Как скрыть верхнюю шапку где находятся кнопки управления приложения
(закрыть/свернуть/расширить), но в тоже время можно было бы перемещать приложение. 

Как саму шапку скрыть я понял, но как сделать чтобы можно было бы при этом перемещать
приложение 

import sys
from PyQt5 import QtWidgets, QtCore

app = QtWidgets.QApplication(sys.argv)

w = QtWidgets.QMainWindow()
w.setWindowFlags(QtCore.Qt.FramelessWindowHint)
w.show()
sys.exit(app.exec_())

    


Ответы

Ответ 1



Пример: from PyQt5.QtWidgets import QWidget, QApplication from PyQt5.QtCore import Qt class Widget(QWidget): def __init__(self): super().__init__() self.setWindowFlags(Qt.FramelessWindowHint) self.old_pos = None def mousePressEvent(self, event): if event.button() == Qt.LeftButton: self.old_pos = event.pos() def mouseReleaseEvent(self, event): if event.button() == Qt.LeftButton: self.old_pos = None def mouseMoveEvent(self, event): if not self.old_pos: return delta = event.pos() - self.old_pos self.move(self.pos() + delta) if __name__ == '__main__': app = QApplication([]) w = Widget() w.show() app.exec()

Ответ 2



Принцип простой. Тебе надо отследить нажатие левой кнопки мыши на любом элементе, хоть на всей форме. Сохранить координаты. Далее отслеживать движение мыши, брать ее координаты относительно всего экрана, вычесть из них сохраненные координаты, и установить позицию формы в получившиеся координаты. Ничего сложного тут нет.

пятница, 28 февраля 2020 г.

Как работать с заголовком окна?

#python #pyqt5


Хочу модернизировать заголовок окна. Например цвет заголовка и хочу добавить еще
одну собственную кнопку. Как это реализовать? Чтоб не было вечно такого:


Пример:
Запускающий файл

import sys, os, time, random
from PyQt5 import QtWidgets, QtCore, QtGui
from PyQt5.QtCore import Qt, pyqtSignal
from MainWindow import Ui_MainWindow

# стиль
StyleSheet = """
/* Панель заголовка */
TitleBar {
    background-color: #2a3440;
}
/* Минимизировать кнопку `Максимальное выключение` Общий фон по умолчанию */
#buttonMinimum,#buttonMaximum,#buttonClose, #buttonMy {
    border: none;
    background-color: #2a3440;
}
/* Зависание */
#buttonMinimum:hover,#buttonMaximum:hover {
    background-color: #2a3440;
}
#buttonClose:hover {
    color: white;
    background-color: #2a3440;
}
#buttonMy:hover {
    color: white;
    background-color: green;   /* rgb(232, 17, 35) */
}
/* Мышь удерживать */
#buttonMinimum:pressed,#buttonMaximum:pressed {
    background-color: #2a3440;
}
#buttonClose:pressed {
    color: white;
    background-color: #2a3440;
}
"""

class Window(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super(Window, self).__init__(parent)
        self.Window = Ui_MainWindow()
        self.Window.setupUi(self)
        self.show()


if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    app.setStyleSheet(StyleSheet)
    Win = Window()
    Win.show()
    sys.exit(app.exec_())


Сам файл накиданный в дизайнере

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'MainWindow.ui'
#
# Created by: PyQt5 UI code generator 5.9.2
#
# WARNING! All changes made in this file will be lost!

from PyQt5 import QtCore, QtGui, QtWidgets

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(257, 60)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.pushButton = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton.setGeometry(QtCore.QRect(160, 20, 75, 23))
        self.pushButton.setObjectName("pushButton")
        self.lineEdit = QtWidgets.QLineEdit(self.centralwidget)
        self.lineEdit.setGeometry(QtCore.QRect(20, 20, 113, 20))
        self.lineEdit.setObjectName("lineEdit")
        MainWindow.setCentralWidget(self.centralwidget)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.pushButton.setText(_translate("MainWindow", "PushButton"))

    


Ответы

Ответ 1



Отличный пример демонстрации как это делается: main.py #!/usr/bin/env python # -*- coding: utf-8 -*- from PyQt5.QtGui import QIcon from PyQt5.QtWidgets import QWidget, QVBoxLayout, QPushButton, QTextEdit from PyQt5.QtCore import pyqtSignal from FramelessWindow import FramelessWindow # Created on 2018年4月30日 # author: Irony # site: https://github.com/892768447 # email: 892768447@qq.com # file: Test # description: __Author__ = """By: Irony QQ: 892768447 Email: 892768447@qq.com""" __Copyright__ = 'Copyright (c) 2018 Irony' __Version__ = 1.0 class MainWindow(QWidget): def __init__(self, *args, **kwargs): super(MainWindow, self).__init__(*args, **kwargs) objectTitleBar = args[0].titleBar layout = QVBoxLayout(self, spacing=0) layout.setContentsMargins(0, 0, 0, 0) layout.addWidget(QPushButton('Кнопка', self)) self.textEdit = QTextEdit(self) layout.addWidget(self.textEdit) objectTitleBar.signalButtonMy.connect(self.onButtonMy) def onButtonMy(self): self.textEdit.append("Нажата `Своя Кнопка`!") # стиль StyleSheet = """ /* Панель заголовка */ TitleBar { background-color: rgb(54, 157, 180); } /* Минимизировать кнопку `Максимальное выключение` Общий фон по умолчанию */ #buttonMinimum,#buttonMaximum,#buttonClose, #buttonMy { border: none; background-color: rgb(54, 157, 180); } /* Зависание */ #buttonMinimum:hover,#buttonMaximum:hover { background-color: rgb(48, 141, 162); } #buttonClose:hover { color: white; background-color: rgb(232, 17, 35); } #buttonMy:hover { color: white; background-color: green; /* rgb(232, 17, 35) */ } /* Мышь удерживать */ #buttonMinimum:pressed,#buttonMaximum:pressed { background-color: rgb(44, 125, 144); } #buttonClose:pressed { color: white; background-color: rgb(161, 73, 92); } """ if __name__ == '__main__': import sys from PyQt5.QtWidgets import QApplication app = QApplication(sys.argv) app.setStyleSheet(StyleSheet) w = FramelessWindow() w.setWindowTitle('Тестовая строка заголовка') w.setWindowIcon(QIcon('Qt.ico')) w.setWidget(MainWindow(w)) # Добавить свое окно w.show() sys.exit(app.exec_()) FramelessWindow.py #!/usr/bin/env python # -*- coding: utf-8 -*- from PyQt5.QtCore import Qt, pyqtSignal, QPoint from PyQt5.QtGui import QFont, QEnterEvent, QPainter, QColor, QPen from PyQt5.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QLabel, QSpacerItem, QSizePolicy, QPushButton) # Created on 2018年4月30日 # author: Irony # site: https://github.com/892768447 # email: 892768447@qq.com # file: FramelessWindow # description: __Author__ = """By: Irony QQ: 892768447 Email: 892768447@qq.com""" __Copyright__ = 'Copyright (c) 2018 Irony' __Version__ = 1.0 class TitleBar(QWidget): # Сигнал минимизации окна windowMinimumed = pyqtSignal() # увеличить максимальный сигнал окна windowMaximumed = pyqtSignal() # сигнал восстановления окна windowNormaled = pyqtSignal() # сигнал закрытия окна windowClosed = pyqtSignal() # Окно мобильных windowMoved = pyqtSignal(QPoint) # Сигнал Своя Кнопка +++ signalButtonMy = pyqtSignal() def __init__(self, *args, **kwargs): super(TitleBar, self).__init__(*args, **kwargs) # Поддержка настройки фона qss self.setAttribute(Qt.WA_StyledBackground, True) self.mPos = None self.iconSize = 20 # Размер значка по умолчанию # Установите цвет фона по умолчанию, иначе он будет прозрачным из-за влияния родительского окна self.setAutoFillBackground(True) palette = self.palette() palette.setColor(palette.Window, QColor(240, 240, 240)) self.setPalette(palette) # макет layout = QHBoxLayout(self, spacing=0) layout.setContentsMargins(0, 0, 0, 0) # значок окна self.iconLabel = QLabel(self) # self.iconLabel.setScaledContents(True) layout.addWidget(self.iconLabel) # название окна self.titleLabel = QLabel(self) self.titleLabel.setMargin(2) layout.addWidget(self.titleLabel) # Средний телескопический бар layout.addSpacerItem(QSpacerItem( 40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)) # Использовать шрифты Webdings для отображения значков font = self.font() or QFont() font.setFamily('Webdings') # Своя Кнопка ++++++++++++++++++++++++++ self.buttonMy = QPushButton( '@', self, clicked=self.showButtonMy, font=font, objectName='buttonMy') layout.addWidget(self.buttonMy) # Свернуть кнопку self.buttonMinimum = QPushButton( '0', self, clicked=self.windowMinimumed.emit, font=font, objectName='buttonMinimum') layout.addWidget(self.buttonMinimum) # Кнопка Max / restore self.buttonMaximum = QPushButton( '1', self, clicked=self.showMaximized, font=font, objectName='buttonMaximum') layout.addWidget(self.buttonMaximum) # Кнопка закрытия self.buttonClose = QPushButton( 'r', self, clicked=self.windowClosed.emit, font=font, objectName='buttonClose') layout.addWidget(self.buttonClose) # начальная высота self.setHeight() # +++ Вызывается по нажатию кнопки buttonMy def showButtonMy(self): print("Своя Кнопка ") self.signalButtonMy.emit() def showMaximized(self): if self.buttonMaximum.text() == '1': # Максимизировать self.buttonMaximum.setText('2') self.windowMaximumed.emit() else: # Восстановить self.buttonMaximum.setText('1') self.windowNormaled.emit() def setHeight(self, height=38): """ Установка высоты строки заголовка """ self.setMinimumHeight(height) self.setMaximumHeight(height) # Задайте размер правой кнопки ? self.buttonMinimum.setMinimumSize(height, height) self.buttonMinimum.setMaximumSize(height, height) self.buttonMaximum.setMinimumSize(height, height) self.buttonMaximum.setMaximumSize(height, height) self.buttonClose.setMinimumSize(height, height) self.buttonClose.setMaximumSize(height, height) self.buttonMy.setMinimumSize(height, height) self.buttonMy.setMaximumSize(height, height) def setTitle(self, title): """ Установить заголовок """ self.titleLabel.setText(title) def setIcon(self, icon): """ настройки значокa """ self.iconLabel.setPixmap(icon.pixmap(self.iconSize, self.iconSize)) def setIconSize(self, size): """ Установить размер значка """ self.iconSize = size def enterEvent(self, event): self.setCursor(Qt.ArrowCursor) super(TitleBar, self).enterEvent(event) def mouseDoubleClickEvent(self, event): super(TitleBar, self).mouseDoubleClickEvent(event) self.showMaximized() def mousePressEvent(self, event): """ Событие клика мыши """ if event.button() == Qt.LeftButton: self.mPos = event.pos() event.accept() def mouseReleaseEvent(self, event): ''' Событие отказов мыши ''' self.mPos = None event.accept() def mouseMoveEvent(self, event): if event.buttons() == Qt.LeftButton and self.mPos: self.windowMoved.emit(self.mapToGlobal(event.pos() - self.mPos)) event.accept() # Перечислить верхнюю левую, нижнюю правую и четыре неподвижные точки Left, Top, Right, Bottom, LeftTop, RightTop, LeftBottom, RightBottom = range(8) class FramelessWindow(QWidget): # Четыре периметра Margins = 5 def __init__(self, *args, **kwargs): super(FramelessWindow, self).__init__(*args, **kwargs) self._pressed = False self.Direction = None # Фон прозрачный self.setAttribute(Qt.WA_TranslucentBackground, True) # Нет границы self.setWindowFlag(Qt.FramelessWindowHint) # Отслеживание мыши self.setMouseTracking(True) # макет layout = QVBoxLayout(self, spacing=0) # Зарезервировать границы для изменения размера окна без полей layout.setContentsMargins( self.Margins, self.Margins, self.Margins, self.Margins) # Панель заголовка self.titleBar = TitleBar(self) layout.addWidget(self.titleBar) # слот сигнала self.titleBar.windowMinimumed.connect(self.showMinimized) self.titleBar.windowMaximumed.connect(self.showMaximized) self.titleBar.windowNormaled.connect(self.showNormal) self.titleBar.windowClosed.connect(self.close) self.titleBar.windowMoved.connect(self.move) self.windowTitleChanged.connect(self.titleBar.setTitle) self.windowIconChanged.connect(self.titleBar.setIcon) def setTitleBarHeight(self, height=38): """ Установка высоты строки заголовка """ self.titleBar.setHeight(height) def setIconSize(self, size): """ Установка размера значка """ self.titleBar.setIconSize(size) def setWidget(self, widget): """ Настройте свои собственные элементы управления """ if hasattr(self, '_widget'): return self._widget = widget # Установите цвет фона по умолчанию, иначе он будет прозрачным из-за влияния родительского окна self._widget.setAutoFillBackground(True) palette = self._widget.palette() palette.setColor(palette.Window, QColor(240, 240, 240)) self._widget.setPalette(palette) self._widget.installEventFilter(self) self.layout().addWidget(self._widget) def move(self, pos): if self.windowState() == Qt.WindowMaximized or self.windowState() == Qt.WindowFullScreen: # Максимизировать или полноэкранный режим не допускается return super(FramelessWindow, self).move(pos) def showMaximized(self): """ Чтобы максимизировать, удалите верхнюю, нижнюю, левую и правую границы. Если вы не удалите его, в пограничной области будут пробелы. """ super(FramelessWindow, self).showMaximized() self.layout().setContentsMargins(0, 0, 0, 0) def showNormal(self): """ Восстановить, сохранить верхнюю и нижнюю левую и правую границы, иначе нет границы, которую нельзя отрегулировать """ super(FramelessWindow, self).showNormal() self.layout().setContentsMargins( self.Margins, self.Margins, self.Margins, self.Margins) def eventFilter(self, obj, event): """ Фильтр событий, используемый для решения мыши в других элементах управления и восстановления стандартного стиля мыши """ if isinstance(event, QEnterEvent): self.setCursor(Qt.ArrowCursor) return super(FramelessWindow, self).eventFilter(obj, event) def paintEvent(self, event): """ Поскольку это полностью прозрачное фоновое окно, жесткая для поиска граница с прозрачностью 1 рисуется в событии перерисовывания, чтобы отрегулировать размер окна. """ super(FramelessWindow, self).paintEvent(event) painter = QPainter(self) painter.setPen(QPen(QColor(255, 255, 255, 1), 2 * self.Margins)) painter.drawRect(self.rect()) def mousePressEvent(self, event): """ Событие клика мыши """ super(FramelessWindow, self).mousePressEvent(event) if event.button() == Qt.LeftButton: self._mpos = event.pos() self._pressed = True def mouseReleaseEvent(self, event): ''' Событие отказов мыши ''' super(FramelessWindow, self).mouseReleaseEvent(event) self._pressed = False self.Direction = None def mouseMoveEvent(self, event): """ Событие перемещения мыши """ super(FramelessWindow, self).mouseMoveEvent(event) pos = event.pos() xPos, yPos = pos.x(), pos.y() wm, hm = self.width() - self.Margins, self.height() - self.Margins if self.isMaximized() or self.isFullScreen(): self.Direction = None self.setCursor(Qt.ArrowCursor) return if event.buttons() == Qt.LeftButton and self._pressed: self._resizeWidget(pos) return if xPos <= self.Margins and yPos <= self.Margins: # Верхний левый угол self.Direction = LeftTop self.setCursor(Qt.SizeFDiagCursor) elif wm <= xPos <= self.width() and hm <= yPos <= self.height(): # Нижний правый угол self.Direction = RightBottom self.setCursor(Qt.SizeFDiagCursor) elif wm <= xPos and yPos <= self.Margins: # верхний правый угол self.Direction = RightTop self.setCursor(Qt.SizeBDiagCursor) elif xPos <= self.Margins and hm <= yPos: # Нижний левый угол self.Direction = LeftBottom self.setCursor(Qt.SizeBDiagCursor) elif 0 <= xPos <= self.Margins and self.Margins <= yPos <= hm: # Влево self.Direction = Left self.setCursor(Qt.SizeHorCursor) elif wm <= xPos <= self.width() and self.Margins <= yPos <= hm: # Право self.Direction = Right self.setCursor(Qt.SizeHorCursor) elif self.Margins <= xPos <= wm and 0 <= yPos <= self.Margins: # выше self.Direction = Top self.setCursor(Qt.SizeVerCursor) elif self.Margins <= xPos <= wm and hm <= yPos <= self.height(): # ниже self.Direction = Bottom self.setCursor(Qt.SizeVerCursor) def _resizeWidget(self, pos): """ Отрегулируйте размер окна """ if self.Direction == None: return mpos = pos - self._mpos xPos, yPos = mpos.x(), mpos.y() geometry = self.geometry() x, y, w, h = geometry.x(), geometry.y(), geometry.width(), geometry.height() if self.Direction == LeftTop: # Верхний левый угол if w - xPos > self.minimumWidth(): x += xPos w -= xPos if h - yPos > self.minimumHeight(): y += yPos h -= yPos elif self.Direction == RightBottom: # Нижний правый угол if w + xPos > self.minimumWidth(): w += xPos self._mpos = pos if h + yPos > self.minimumHeight(): h += yPos self._mpos = pos elif self.Direction == RightTop: # верхний правый угол if h - yPos > self.minimumHeight(): y += yPos h -= yPos if w + xPos > self.minimumWidth(): w += xPos self._mpos.setX(pos.x()) elif self.Direction == LeftBottom: # Нижний левый угол if w - xPos > self.minimumWidth(): x += xPos w -= xPos if h + yPos > self.minimumHeight(): h += yPos self._mpos.setY(pos.y()) elif self.Direction == Left: # Влево if w - xPos > self.minimumWidth(): x += xPos w -= xPos else: return elif self.Direction == Right: # Право if w + xPos > self.minimumWidth(): w += xPos self._mpos = pos else: return elif self.Direction == Top: # выше if h - yPos > self.minimumHeight(): y += yPos h -= yPos else: return elif self.Direction == Bottom: # ниже if h + yPos > self.minimumHeight(): h += yPos self._mpos = pos else: return self.setGeometry(x, y, w, h)

среда, 26 февраля 2020 г.

Почему не обновляется виджет с чатом QListWidget?

#python #python_3x #pyqt5 #pyqt


Есть такой код, для простоты лишнее не привожу. После авторизации срабатывает метод
getChat и выводится виджет с сообщениями, которые берутся из базы. В другом потоке
отправляются запросы на сервер каждую секунду и в консоли вижу, что нужный словарь
с данными при отправке нового сообщения как и нужно обновляется и возвращается в переменной
rs. Далее пытаюсь перерисовать виджет с сообщениями, наверное это нужно делать в методе
on_request, но не получается. Прошу подсказать, ума не приложу, как это реализовать. 

from PyQt5 import QtCore, QtWidgets, QtGui
from PyQt5.QtCore import QThread
import requests
import json
import time

colors = ['#1f3a93', '#26a65b']

class ThreadClass(QThread):
    about_response = QtCore.pyqtSignal(object)

    def __init__(self, url: str):
        super().__init__()
        self.url = url

    def run(self):
        while True:
            try:
                rs = requests.post(self.url)
                self.about_response.emit(rs)

            except Exception as e:
                print('Error:', e)

            finally:
                time.sleep(3)

class MyWindow(QtWidgets.QWidget):

    def __init__(self, parent=None):
        QtWidgets.QWidget.__init__(self, parent)

        self.url_base = 'http://127.0.0.1:5000/'
        self.main_id = 0
        self.res_usr = {}
        self.chat_obj = QtWidgets.QListWidget


        url = self.url_base + 'blog/chat'

        self.thread_class = ThreadClass(url)
        self.thread_class.about_response.connect(self.on_response)
        self.thread_class.start()

        self.title = QtWidgets.QLabel('Авторизация')
        self.title.setAlignment(QtCore.Qt.AlignHCenter)

        self.username = QtWidgets.QLineEdit()
        self.username.setPlaceholderText('Введите логин:')
        self.password = QtWidgets.QLineEdit()
        self.password.setPlaceholderText('Введите пароль:'),
        self.password.setEchoMode(QtWidgets.QLineEdit.Password)
        self.btnLogin = QtWidgets.QPushButton("&OK")

        self.lnkReg = QtWidgets.QPushButton('&Регистрация')

        self.vbox = QtWidgets.QVBoxLayout()
        self.vbox.addWidget(self.title)
        self.vbox.addWidget(self.username)
        self.vbox.addWidget(self.password)
        self.vbox.addWidget(self.btnLogin)
        self.vbox.addWidget(self.lnkReg)

        self.setLayout(self.vbox)
        self.btnLogin.clicked.connect(self.authorisation)
        self.lnkReg.clicked.connect(self.switchToRegistration)

    def on_response(self, rs):
        res_u = rs.text
        res_pst = json.loads(res_u)
        print(res_pst)
        self.chat_obj = QtWidgets.QListWidget(self)
        for key, value in res_pst.items():
            item = QtWidgets.QListWidgetItem(self.chat_obj)
            item.setText(value[0] + ': ' + value[1])
            if value[2] == self.main_id:
                item.setTextAlignment(QtCore.Qt.AlignRight)
                item.setForeground(QtGui.QColor(colors[0]))
            else:
                item.setTextAlignment(QtCore.Qt.AlignLeft)
                item.setForeground(QtGui.QColor(colors[1]))
            self.chat_obj.addItem(value[0] + ': ' + value[1])
        self.chat_obj.repaint()



    def switchToRegistration(self):
        """
        Переключение на регистрацию
        """
        window.resize(300, 200)
        self.clearLayout(self.vbox)

        self.title = QtWidgets.QLabel('Регистрация')
        self.title.setAlignment(QtCore.Qt.AlignHCenter)

        self.username = QtWidgets.QLineEdit()
        self.username.setPlaceholderText('Введите логин:')
        self.password = QtWidgets.QLineEdit()
        self.password.setPlaceholderText('Введите пароль:'),
        self.password.setEchoMode(QtWidgets.QLineEdit.Password)
        self.btnReg = QtWidgets.QPushButton("&OK")

        self.lnkAutor = QtWidgets.QPushButton('&Авторизация')

        self.vbox.addWidget(self.title)
        self.vbox.addWidget(self.username)
        self.vbox.addWidget(self.password)
        self.vbox.addWidget(self.btnReg)
        self.vbox.addWidget(self.lnkAutor)

        self.setLayout(self.vbox)
        self.btnReg.clicked.connect(self.registration)
        self.lnkAutor.clicked.connect(self.switchToAuthorisation)


    def switchToAuthorisation(self):
        """
        Переключение на авторизацию
        """
        window.resize(300, 200)
        self.clearLayout(self.vbox)

        self.title = QtWidgets.QLabel('Авторизация')
        self.title.setAlignment(QtCore.Qt.AlignHCenter)

        self.username = QtWidgets.QLineEdit()
        self.username.setPlaceholderText('Введите логин:')
        self.password = QtWidgets.QLineEdit()
        self.password.setPlaceholderText('Введите пароль:'),
        self.password.setEchoMode(QtWidgets.QLineEdit.Password)
        self.btnAutor = QtWidgets.QPushButton("&OK")

        self.lnkReg = QtWidgets.QPushButton('&Регистрация')

        self.vbox.addWidget(self.title)
        self.vbox.addWidget(self.username)
        self.vbox.addWidget(self.password)
        self.vbox.addWidget(self.btnLogin)
        self.vbox.addWidget(self.lnkReg)

        self.setLayout(self.vbox)
        self.btnAutor.clicked.connect(self.authorisation)
        self.lnkReg.clicked.connect(self.switchToRegistration)


    def authorisation(self):
        """
        Авторизация
        """
        url = self.url_base + 'auth/login'
        data = {'username': self.username.text(), 'password': self.password.text()}
        r = requests.post(url, json=data)

        res_u = r.text
        #print(res_u)
        res_usr = json.loads(res_u)
        #print(res_usr['status'])
        if res_usr['status'] == 'ok':
            self.main_id = res_usr['id']
            #print(self.main_id)
            self.getChat()
        elif res_usr['status'] == 'no':
            self.showError(res_usr)


    def registration(self):
        """
        Регистрация
        """
        url = self.url_base + 'auth/register'
        data = {'username': self.username.text(), 'password': self.password.text()}
        r = requests.post(url, json=data)

        res_u = r.text
        #print(res_u)
        res_usr = json.loads(res_u)
        if res_usr['status'] == 'ok':
            self.switchToAuthorisation()
        elif res_usr['status'] == 'no':
            self.showError(res_usr)


    def clearLayout(self, layout):
        """
        Очистка окошка
        """
        for i in reversed(range(layout.count())):
            layout.itemAt(i).widget().setParent(None)


    def showError(self, res_usr):
        """
        Показать ошибки
        """
        self.label = QtWidgets.QLabel(res_usr['error'])
        self.label.setAlignment(QtCore.Qt.AlignHCenter)
        self.vbox.addWidget(self.label)

    def showSuccess(self, res_usr):
        """
        Показать успех
        """
        self.label = QtWidgets.QLabel(res_usr['success_msg'])
        self.label.setAlignment(QtCore.Qt.AlignHCenter)
        self.vbox.addWidget(self.label)

    def getChat(self):
        window.resize(300, 400)
        self.clearLayout(self.vbox)

        self.label = QtWidgets.QLabel('Чат')
        self.label.setAlignment(QtCore.Qt.AlignHCenter)
        self.vbox.addWidget(self.label)

        url = self.url_base + 'blog/chat'
        r = requests.post(url)
        print(r.status_code, r.reason)
        print(r.request.headers)

        res_u = r.text
        res_pst = json.loads(res_u)
        #print(res_pst)

        self.chat_obj = QtWidgets.QListWidget(self)
        for key, value in res_pst.items():
            item = QtWidgets.QListWidgetItem(self.chat_obj)
            item.setText(value[0] + ': ' + value[1])
            if value[2] == self.main_id:
                item.setTextAlignment(QtCore.Qt.AlignRight)
                item.setForeground(QtGui.QColor(colors[0]))
            else:
                item.setTextAlignment(QtCore.Qt.AlignLeft)
                item.setForeground(QtGui.QColor(colors[1]))
        #self.chat_obj.addItem(value[0] + ': ' + value[1])

        self.vbox.addWidget(self.chat_obj)

        self.message = QtWidgets.QLineEdit()
        self.message.setPlaceholderText('Введите сообщение')
        self.vbox.addWidget(self.message)

        self.btnSend = QtWidgets.QPushButton("&Отправить")
        self.vbox.addWidget(self.btnSend)
        self.btnSend.clicked.connect(self.sendmessage)


    def sendmessage(self):
        """
        Отправка сообщения
        """
        print(self.main_id)
        url = self.url_base + 'blog/create/{}'.format(self.main_id)
        data = {'message': self.message.text()}
        #print(data)
        r = requests.post(url, json=data)

        #print(r.status_code, r.reason)
        #print(r.request.headers)

        res_m = r.text
        #print(res_m)
        res_usr = json.loads(res_m)
        if res_usr['status'] == 'ok':
            self.showSuccess(res_usr)
        elif res_usr['status'] == 'no':
            self.showError(res_usr)

        self.message.clear()


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    window = MyWindow()
    window.setWindowTitle("Простой Мессенжер")
    window.resize(300, 200)
    window.show()
    sys.exit(app.exec_())


Вот код серверной части, тот, который отвечает за формирование чата:

from flask import (
Blueprint, flash, g, redirect, render_template, request, url_for
)
from werkzeug.exceptions import abort

from flaskr.auth import login_required
from flaskr.db import get_db
import json

bp = Blueprint('blog', __name__, url_prefix='/blog')


@bp.route('/chat', methods=('GET', 'POST'))
def chat():

    db = get_db()
    posts = db.execute(
        'SELECT p.id, author_id, msg, created, u.username'
        ' FROM post p JOIN user u'
        ' ON u.id = p.author_id'
        ' ORDER BY p.created DESC',
    ).fetchall()
    pst = {}
    for i in posts:
        pst[i['id']] = [i['username'], i['msg'], i['author_id']]
    dc = pst
    dc = json.dumps(dc)
    return dc


@bp.route('/create/', methods=('GET', 'POST'))
def create(main_id):
    if request.method == 'POST':
        msg = request.get_json().get('message')
        error = None

        if not msg:
            error = 'Message is required.'

        if error is not None:
            dc = {'error': error, 'status': 'not'}
            dc = json.dumps(dc)
            return dc
        else:
            db = get_db()
            author_id = main_id
            db.execute(
                'INSERT INTO post (msg, author_id)'
                ' VALUES (?, ?)',
                (msg, author_id)
            )
            db.commit()

            dc = {'success_msg': 'The message successfully sent', 'status': 'ok'}
            dc = json.dumps(dc)
            return dc

    return dc

    


Ответы

Ответ 1



Мои изменения рядом с # TODO:. Главное что сделал -- убрал пересоздание виджета-списка и манипуляции с layout (это можно потом сделать, сейчас это будет мешать) class MyWindow(QtWidgets.QWidget): def __init__(self, parent=None): super().__init__(parent) self.url_base = 'http://127.0.0.1:5000/' self.main_id = 0 self.res_usr = dict() # TODO: # self.chat_obj = QtWidgets.QListWidget url = self.url_base + 'blog/chat' self.thread_class = ThreadClass(url) self.thread_class.about_response.connect(self.on_response) self.thread_class.start() self.title = QtWidgets.QLabel('Авторизация') self.title.setAlignment(QtCore.Qt.AlignHCenter) self.username = QtWidgets.QLineEdit() self.username.setPlaceholderText('Введите логин:') self.password = QtWidgets.QLineEdit() self.password.setPlaceholderText('Введите пароль:'), self.password.setEchoMode(QtWidgets.QLineEdit.Password) self.btnLogin = QtWidgets.QPushButton("&OK") self.lnkReg = QtWidgets.QPushButton('&Регистрация') self.chat_obj = QtWidgets.QListWidget() self.vbox = QtWidgets.QVBoxLayout() self.vbox.addWidget(self.title) self.vbox.addWidget(self.username) self.vbox.addWidget(self.password) self.vbox.addWidget(self.btnLogin) self.vbox.addWidget(self.lnkReg) # TODO: # Пусть пока будет self.vbox.addWidget(self.chat_obj) self.setLayout(self.vbox) self.btnLogin.clicked.connect(self.authorisation) self.lnkReg.clicked.connect(self.switchToRegistration) def on_response(self, rs): # TODO: res_pst = rs.json() # res_u = rs.text # res_pst = json.loads(res_u) print(res_pst) for key, value in res_pst.items(): item = QtWidgets.QListWidgetItem(self.chat_obj) item.setText(value[0] + ': ' + value[1]) if value[2] == self.main_id: item.setTextAlignment(QtCore.Qt.AlignRight) item.setForeground(QtGui.QColor(colors[0])) else: item.setTextAlignment(QtCore.Qt.AlignLeft) item.setForeground(QtGui.QColor(colors[1])) self.chat_obj.addItem(value[0] + ': ' + value[1]) def switchToRegistration(self): """ Переключение на регистрацию """ # TODO: self.resize(300, 200) # self.clearLayout(self.vbox) self.title = QtWidgets.QLabel('Регистрация') self.title.setAlignment(QtCore.Qt.AlignHCenter) self.username = QtWidgets.QLineEdit() self.username.setPlaceholderText('Введите логин:') self.password = QtWidgets.QLineEdit() self.password.setPlaceholderText('Введите пароль:'), self.password.setEchoMode(QtWidgets.QLineEdit.Password) self.btnReg = QtWidgets.QPushButton("&OK") self.lnkAutor = QtWidgets.QPushButton('&Авторизация') self.vbox.addWidget(self.title) self.vbox.addWidget(self.username) self.vbox.addWidget(self.password) self.vbox.addWidget(self.btnReg) self.vbox.addWidget(self.lnkAutor) self.setLayout(self.vbox) self.btnReg.clicked.connect(self.registration) self.lnkAutor.clicked.connect(self.switchToAuthorisation) def switchToAuthorisation(self): """ Переключение на авторизацию """ # TODO: self.resize(300, 200) # self.clearLayout(self.vbox) self.title = QtWidgets.QLabel('Авторизация') self.title.setAlignment(QtCore.Qt.AlignHCenter) self.username = QtWidgets.QLineEdit() self.username.setPlaceholderText('Введите логин:') self.password = QtWidgets.QLineEdit() self.password.setPlaceholderText('Введите пароль:'), self.password.setEchoMode(QtWidgets.QLineEdit.Password) self.btnAutor = QtWidgets.QPushButton("&OK") self.lnkReg = QtWidgets.QPushButton('&Регистрация') self.vbox.addWidget(self.title) self.vbox.addWidget(self.username) self.vbox.addWidget(self.password) self.vbox.addWidget(self.btnLogin) self.vbox.addWidget(self.lnkReg) self.setLayout(self.vbox) self.btnAutor.clicked.connect(self.authorisation) self.lnkReg.clicked.connect(self.switchToRegistration) def authorisation(self): """ Авторизация """ url = self.url_base + 'auth/login' data = {'username': self.username.text(), 'password': self.password.text()} r = requests.post(url, json=data) # TODO: res_usr = r.json() # res_u = r.text # #print(res_u) # res_usr = json.loads(res_u) #print(res_usr['status']) if res_usr['status'] == 'ok': self.main_id = res_usr['id'] #print(self.main_id) self.getChat() elif res_usr['status'] == 'no': self.showError(res_usr) def registration(self): """ Регистрация """ url = self.url_base + 'auth/register' data = {'username': self.username.text(), 'password': self.password.text()} r = requests.post(url, json=data) res_usr = r.json() # TODO: # res_u = r.text # #print(res_u) # res_usr = json.loads(res_u) if res_usr['status'] == 'ok': self.switchToAuthorisation() elif res_usr['status'] == 'no': self.showError(res_usr) # TODO: # def clearLayout(self, layout): # """ # Очистка окошка # """ # for i in reversed(range(layout.count())): # layout.itemAt(i).widget().setParent(None) def showError(self, res_usr): """ Показать ошибки """ self.label = QtWidgets.QLabel(res_usr['error']) self.label.setAlignment(QtCore.Qt.AlignHCenter) self.vbox.addWidget(self.label) def showSuccess(self, res_usr): """ Показать успех """ self.label = QtWidgets.QLabel(res_usr['success_msg']) self.label.setAlignment(QtCore.Qt.AlignHCenter) self.vbox.addWidget(self.label) def getChat(self): window.resize(300, 400) # self.clearLayout(self.vbox) self.label = QtWidgets.QLabel('Чат') self.label.setAlignment(QtCore.Qt.AlignHCenter) self.vbox.addWidget(self.label) url = self.url_base + 'blog/chat' r = requests.post(url) print(r.status_code, r.reason) print(r.request.headers) # TODO: res_pst = r.json() # res_u = r.text # res_pst = json.loads(res_u) #print(res_pst) # self.chat_obj = QtWidgets.QListWidget(self) for key, value in res_pst.items(): item = QtWidgets.QListWidgetItem(self.chat_obj) item.setText(value[0] + ': ' + value[1]) if value[2] == self.main_id: item.setTextAlignment(QtCore.Qt.AlignRight) item.setForeground(QtGui.QColor(colors[0])) else: item.setTextAlignment(QtCore.Qt.AlignLeft) item.setForeground(QtGui.QColor(colors[1])) #self.chat_obj.addItem(value[0] + ': ' + value[1]) # TODO: в конструкторе добавлено на форму # self.vbox.addWidget(self.chat_obj) self.message = QtWidgets.QLineEdit() self.message.setPlaceholderText('Введите сообщение') self.vbox.addWidget(self.message) self.btnSend = QtWidgets.QPushButton("&Отправить") self.vbox.addWidget(self.btnSend) self.btnSend.clicked.connect(self.sendmessage) def sendmessage(self): """ Отправка сообщения """ print(self.main_id) url = self.url_base + 'blog/create/{}'.format(self.main_id) data = {'message': self.message.text()} #print(data) r = requests.post(url, json=data) #print(r.status_code, r.reason) #print(r.request.headers) # TODO: res_usr = r.json() # res_m = r.text # #print(res_m) # res_usr = json.loads(res_m) if res_usr['status'] == 'ok': self.showSuccess(res_usr) elif res_usr['status'] == 'no': self.showError(res_usr) self.message.clear() Код с self.label = явно костыльный, но его не трогал, т.к. проблема с QListWidget, а не с этим

пятница, 14 февраля 2020 г.

Отображение изображение на экран PyQt5 доступных в bytes

#python #python_3x #pyqt5


как вывести изображение на экран PyQt5 если изображение храниться в бд в bytes 

import sys,sqlite3
from PyQt5.QtWidgets import QWidget, QApplication,QPushButton
from PyQt5.QtGui import QPainter, QColor, QFont,QIcon
from PyQt5.QtCore import Qt,QSize
class Example(QWidget):

    def __init__(self):
        super().__init__()
        self.initUI()


    def initUI(self):
        conn = sqlite3.connect("test.db")
        connect = conn.execute("SELECT Data from Images")
        for row in connect:

            self.label_im_qrcode = QLabel()
            import io, qrcode
            b = io.BytesIO(row[0])
            img.save(b, 'png')
            data = b.getvalue()

            pixmap = QPixmap()
            pixmap.loadFromData(data)


            self.label_im_qrcode.setPixmap(pixmap)
         self.setGeometry(300, 300, 280, 170)
         self.setWindowTitle('Draw text')
         self.show()
if __name__ == '__main__':
    con = sqlite3.connect('test.db')
    cur = con.cursor()
    fin = open('woman.jpg', "rb")
    img = fin.read()
    binary = sqlite3.Binary(img)
    cur.execute("INSERT INTO Images(Data) VALUES (?)", (binary,))
    con.commit()
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

    


Ответы

Ответ 1



Воспользоваться нужными методами: QImage.loadFromData или QImage::fromData. Для QPixmap есть метод QPixmap.loadFromData Пример из qrcode_gui: text = self.input_text.toPlainText() img = qrcode.make(text) import io b = io.BytesIO() img.save(b, 'png') data = b.getvalue() pixmap = QPixmap() pixmap.loadFromData(data) self.label_im_qrcode.setPixmap(pixmap) Больше моих примеров После обновления вопроса: Показываю пример добавления в базу данных SQLite картинки и отображения ее на виджете Qt: import sys import sqlite3 from PyQt5.QtWidgets import * from PyQt5.QtGui import * if __name__ == '__main__': con = sqlite3.connect('test.sqlite') cur = con.cursor() cur.execute(''' CREATE TABLE IF NOT EXISTS Images ( Data BLOB ) ''') con.commit() with open('capture.png', mode='rb') as f: binary = sqlite3.Binary(f.read()) cur.execute("INSERT INTO Images(Data) VALUES (?)", (binary,)) con.commit() app = QApplication([]) w = QWidget() layout = QVBoxLayout() w.setLayout(layout) for (img_data,) in con.execute("SELECT Data from Images"): pixmap = QPixmap() pixmap.loadFromData(img_data) label = QLabel() label.setPixmap(pixmap) layout.addWidget(label) w.show() sys.exit(app.exec_()) Скриншот:

Реализация Drag&Drop на своем виджете

#python #pyqt5 #pyqt


У меня есть виджет и я хочу сделать какие-нибудь действия с файлами, которые будут
перетащены и брошены на мой виджет.

from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel, QWidget, QVBoxLayout


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        self.setWindowTitle('Drag & Drop')

        main_layout = QVBoxLayout()
        main_layout.addWidget(QLabel('Drag and drop the file:'))
        main_layout.addStretch()

        central_widget = QWidget()
        central_widget.setLayout(main_layout)

        self.setCentralWidget(central_widget)


if __name__ == '__main__':
    app = QApplication([])

    mw = MainWindow()
    mw.resize(500, 350)
    mw.show()

    app.exec()

    


Ответы

Ответ 1



Как вариант: from PyQt5.QtWidgets import (QTreeView, QFileSystemModel, QApplication, QMainWindow, QLabel, QWidget, QVBoxLayout, QListWidget) from PyQt5.QtCore import QDir class MainWindow(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle('Drag & Drop') self.setGeometry(500, 100, 500, 400) # Даем разрешение на Drop self.setAcceptDrops(True) self.list_files = QListWidget() self.label_total_files = QLabel() model = QFileSystemModel() model.setRootPath(QDir.currentPath()) model.setReadOnly(False) self.tree = QTreeView() self.tree.setModel(model) self.tree.setRootIndex(model.index(QDir.currentPath())) self.tree.setSelectionMode(QTreeView.SingleSelection) self.tree.setDragDropMode(QTreeView.InternalMove) main_layout = QVBoxLayout() main_layout.addWidget(self.tree) main_layout.addWidget(QLabel('Перетащите файл:')) main_layout.addWidget(self.list_files) main_layout.addWidget(self.label_total_files) central_widget = QWidget() central_widget.setLayout(main_layout) self.setCentralWidget(central_widget) self._update_states() def _update_states(self): self.label_total_files.setText('Files: {}'.format(self.list_files.count())) def dragEnterEvent(self, event): # Тут выполняются проверки и дается (или нет) разрешение на Drop mime = event.mimeData() # Если перемещаются ссылки if mime.hasUrls(): # Разрешаем event.acceptProposedAction() def dropEvent(self, event): # Обработка события Drop for url in event.mimeData().urls(): file_name = url.toLocalFile() self.list_files.addItem(file_name) self._update_states() return super().dropEvent(event) if __name__ == '__main__': import sys app = QApplication(sys.argv) w = MainWindow() w.show() sys.exit(app.exec_())

Ответ 2



Минимальная реализация Drag&Drop потребует следующих шагов: Вызов метода setAcceptDrops и передача ему True разрешает виджету обрабатывать события Drop. Переопределение метода-события dragEnterEvent позволит принимать объекты Drag и, при нужде, фильтровать их по какому-либо признаку. Переопределение метода-события dropEvent позволит обработать сброшенные объекты. В этом примере виджет будет принимать на себя папки и файлы, и добавлять их в свой список. Код: from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel, QWidget, QVBoxLayout, QListWidget class MainWindow(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle('Drag & Drop') # Даем разрешение на Drop self.setAcceptDrops(True) self.list_files = QListWidget() self.label_total_files = QLabel() main_layout = QVBoxLayout() main_layout.addWidget(QLabel('Drag and drop the file:')) main_layout.addWidget(self.list_files) main_layout.addWidget(self.label_total_files) central_widget = QWidget() central_widget.setLayout(main_layout) self.setCentralWidget(central_widget) self._update_states() def _update_states(self): self.label_total_files.setText('Files: {}'.format(self.list_files.count())) def dragEnterEvent(self, event): # Тут выполняются проверки и дается (или нет) разрешение на Drop mime = event.mimeData() # Если перемещаются ссылки if mime.hasUrls(): # Разрешаем event.acceptProposedAction() def dropEvent(self, event): # Обработка события Drop for url in event.mimeData().urls(): file_name = url.toLocalFile() self.list_files.addItem(file_name) self._update_states() return super().dropEvent(event) if __name__ == '__main__': app = QApplication([]) mw = MainWindow() mw.resize(500, 350) mw.show() app.exec() Скриншот: PS. если интересно, тут есть пример Drag&Drop, в котором обрабатывается строго 1 файл и после сброса подсчитывается его md5-хеш.

среда, 5 февраля 2020 г.

Python PyQt5 запуск Qt Designer в Windows 7

#pyqt5 #python_36


PyQt5 поставил так: pip3 install PyQt5 - установился нормально.
Но как запустить Qt Designer?
    


Ответы

Ответ 1



Поищите в <папка python>\Library\bin\designer.exe Если его там нет, попробуйте установить: pip install pyqt5-tools. Тогда дизайнер искать в: <папка python>\Lib\site-packages\pyqt5-tools\designer.exe

Ответ 2



Может быть вы смотрели в папке с установленным Python, а не в документах: C:\Users\Username\AppData\Local\Programs\Python... pyqt5_tools\ Qt\ bin Нашел там, после совета с установкой через команду: pip install pyqt5-tools от пользователя выше.

вторник, 28 января 2020 г.

Правильность импртов PyQt

#python #python_3x #pyqt5


Какие из ниже перечисленных импортов являются более правильными по скорости и по
читаемости. 

1 вариант

import sys
from PyQt5.QtWidgets import *


class Io(QWidget):
    def __init__(self):
        super().__init__()
        b = QCommandLinkButton("Переход")
        layout = QVBoxLayout()
        layout.addWidget(b)
        self.setLayout(layout)
        self.show()


if __name__ == "__main__":
    app = QApplication(sys.argv)
    main = Io()
    sys.exit(app.exec_())




2 вариант

import sys
from PyQt5 import QtWidgets


class Io(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()
        b = QtWidgets.QCommandLinkButton("Переход")
        layout = QtWidgets.QVBoxLayout()
        layout.addWidget(b)
        self.setLayout(layout)
        self.show()


if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    main = Io()
    sys.exit(app.exec_())




3 вариант

import sys
from PyQt5.QtWidgets import QWidget, QApplication, QVBoxLayout, QCommandLinkButton


class Io(QWidget):
    def __init__(self):
        super().__init__()
        b = QCommandLinkButton("Переход")
        layout = QVBoxLayout()
        layout.addWidget(b)
        self.setLayout(layout)
        self.show()


if __name__ == "__main__":
    app = QApplication(sys.argv)
    main = Io()
    sys.exit(app.exec_())

    


Ответы

Ответ 1



Есть замечательное правило, действующее во многих командах "Заимпортил звёздочку - получил по мордочке". А выбор между вторым и третьим вариантом - пожалуй, дело вкуса.

Ответ 2



Если вы хотите все qt имена в одном пространство имён импортировать, можно Qt использовать: from PyQt5 import Qt Это позволяет писать: Qt.QApplication, Qt.QPoint, Qt.QPainter, etc. Недостаток, что все qt модули импортируются, увеличивая время загрузки и потребляемую память, если фактически вам нужны только отдельные модули. Не используйте from module import * за исключением специальных случаев: в REPL или в __init__.py файле. Пример оправданного использования: asyncio/__init__.py—asyncio предоставляет "плоский" публичный интерфейс (имена доступны прямо как asyncio.name), не смотря на то что реализация распределена по многочисленным вложенным модулям. Можно ли отнести импорты pyqt к специальным случаям, зависит могут ли конфликтующие имена появиться сегодня и в будущем (если все имена в __all__ начинаются с Q*, то нет опасности, что вы их перепутаете со своими). Не применяйте правила вслепую, используйте голову PEP-8: "A Foolish Consistency is the Hobgoblin of Little Minds."

пятница, 24 января 2020 г.

Вывод в окне QPlainTextEdit pyqt5 сообщения из модуля logging.Поток pyqt5.Логирование

#python #многопоточность #pyqt5 #логирование


Как сделать так что-бы сообщения из модуля logging выходили в окне QPlainTextEdit.Желательно
показать на моём примере как из потока вывести сообщение по завершению действия функции,так
и без потока.По сути логирование программы.


# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'stacword.ui'
#
# Created by: PyQt5 UI code generator 5.11.3
#
# WARNING! All changes made in this file will be lost!
import logging
import sys
from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(316, 324)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.pushButton = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton.setGeometry(QtCore.QRect(110, 240, 75, 23))
        self.pushButton.setObjectName("pushButton")
        self.plainTextEdit = QtWidgets.QPlainTextEdit(self.centralwidget)
        self.plainTextEdit.setGeometry(QtCore.QRect(10, 10, 291, 131))
        self.plainTextEdit.setObjectName("plainTextEdit")
        self.label = QtWidgets.QLabel(self.centralwidget)
        self.label.setGeometry(QtCore.QRect(130, 180, 47, 13))
        self.label.setObjectName("label")
        MainWindow.setCentralWidget(self.centralwidget)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.pushButton.setText(_translate("MainWindow", "PushButton"))
        self.label.setText(_translate("MainWindow", "TextLabel"))


class ExampleApp(QtWidgets.QMainWindow, Ui_MainWindow):
    def __init__(self):
        super().__init__()

        self.setupUi(self)

        self.plainTextEdit.setTextInteractionFlags(QtCore.Qt.TextSelectableByMouse)
# Делает QPlainTextEdit только для вывода

        self.thread = WorkThread()

        self.pushButton.clicked.connect(self.func1)

        logging.basicConfig(level=logging.DEBUG)

        logging.info(u'This is an info message')

    def func1(self):
        # Создаем поток
        self.thread.start()


class WorkThread(QtCore.QThread):
    ''' Потоковая задача '''
    threadSignal = QtCore.pyqtSignal(int)

    def __init__(self):
        super().__init__()

    def run(self):     # После окончания работы этой фукции в потоке,вывести сообщение
от модуля logging в QPlainTextEdit
        for i in range(10):
            self.msleep(200)
            print(i)
            self.threadSignal.emit(i)


def main():
    app = QtWidgets.QApplication(sys.argv)  # Новый экземпляр QApplication
    window = ExampleApp()  # Создаём объект класса ExampleApp
    window.show()  # Показываем окно
    app.exec_()


if __name__ == '__main__':
    main()


    


Ответы

Ответ 1



Как вариант: import logging import sys from PyQt5 import QtCore, QtGui, QtWidgets class Ui_MainWindow(object): def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") MainWindow.resize(316, 324) self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") self.pushButton = QtWidgets.QPushButton(self.centralwidget) self.pushButton.setGeometry(QtCore.QRect(110, 240, 75, 23)) self.pushButton.setObjectName("pushButton") self.plainTextEdit = QtWidgets.QPlainTextEdit(self.centralwidget) self.plainTextEdit.setGeometry(QtCore.QRect(10, 10, 291, 131)) self.plainTextEdit.setObjectName("plainTextEdit") self.label = QtWidgets.QLabel(self.centralwidget) self.label.setGeometry(QtCore.QRect(130, 180, 47, 13)) self.label.setObjectName("label") MainWindow.setCentralWidget(self.centralwidget) self.retranslateUi(MainWindow) QtCore.QMetaObject.connectSlotsByName(MainWindow) def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow")) self.pushButton.setText(_translate("MainWindow", "PushButton")) self.label.setText(_translate("MainWindow", "TextLabel")) # +++ vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv class QTextEditLogger(logging.Handler): def __init__(self, parent): super().__init__() self.widget = parent.plainTextEdit self.widget.setReadOnly(True) def emit(self, record): msg = self.format(record) self.widget.appendPlainText(msg) # +++ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ class ExampleApp(QtWidgets.QMainWindow, Ui_MainWindow): def __init__(self): super().__init__() self.setupUi(self) # +++ vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv logTextBox = QTextEditLogger(self) logTextBox.setFormatter(logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')) logging.getLogger().addHandler(logTextBox) logging.getLogger().setLevel(logging.DEBUG) # +++ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ # Делает QPlainTextEdit только для вывода self.plainTextEdit.setTextInteractionFlags(QtCore.Qt.TextSelectableByMouse) self.thread = WorkThread() self.thread.threadSignal.connect(self.func2) # +++ self.pushButton.clicked.connect(self.func1) logging.debug("Это сообщение об отладке") logging.info(u'This is an info message') def func1(self): # Создаем поток self.thread.start() def func2(self, value): # +++ logging.info("Передано из потока -> {}".format(value)) # +++ class WorkThread(QtCore.QThread): ''' Потоковая задача ''' threadSignal = QtCore.pyqtSignal(int) def __init__(self): super().__init__() def run(self): for i in range(10): self.msleep(200) # print(i) self.threadSignal.emit(i) def main(): app = QtWidgets.QApplication(sys.argv) window = ExampleApp() window.show() app.exec_() if __name__ == '__main__': main() каким образом можно вывести сообщение по завершению действия в потоке? import logging import sys from PyQt5 import QtCore, QtGui, QtWidgets class Ui_MainWindow(object): def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") MainWindow.resize(400, 324) self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") self.pushButton = QtWidgets.QPushButton(self.centralwidget) self.pushButton.setGeometry(QtCore.QRect(110, 240, 75, 23)) self.pushButton.setObjectName("pushButton") self.plainTextEdit = QtWidgets.QPlainTextEdit(self.centralwidget) self.plainTextEdit.setGeometry(QtCore.QRect(10, 10, 370, 131)) self.plainTextEdit.setObjectName("plainTextEdit") self.label = QtWidgets.QLabel(self.centralwidget) self.label.setGeometry(QtCore.QRect(130, 180, 47, 13)) self.label.setObjectName("label") MainWindow.setCentralWidget(self.centralwidget) self.retranslateUi(MainWindow) QtCore.QMetaObject.connectSlotsByName(MainWindow) def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow")) self.pushButton.setText(_translate("MainWindow", "PushButton")) self.label.setText(_translate("MainWindow", "TextLabel")) class QTextEditLogger(logging.Handler): def __init__(self, parent): super().__init__() self.widget = parent.plainTextEdit self.widget.setReadOnly(True) def emit(self, record): msg = self.format(record) self.widget.appendPlainText(msg) class ExampleApp(QtWidgets.QMainWindow, Ui_MainWindow): def __init__(self): super().__init__() self.setupUi(self) logTextBox = QTextEditLogger(self) logTextBox.setFormatter(logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')) logging.getLogger().addHandler(logTextBox) logging.getLogger().setLevel(logging.DEBUG) layout = QtWidgets.QVBoxLayout(self.centralwidget) # +++ layout.addWidget(self.plainTextEdit) layout.addWidget(self.label) layout.addWidget(self.pushButton) self.plainTextEdit.setTextInteractionFlags(QtCore.Qt.TextSelectableByMouse) self.thread = WorkThread() self.thread.threadSignal.connect(self.func2) self.thread.finishSignal.connect(self.func3) # +++ self.pushButton.clicked.connect(self.func1) logging.debug("Это сообщение об отладке") logging.info('This is an info message') def func1(self): # Создаем поток self.thread.start() def func2(self, value): logging.info("Передано из потока -> {}".format(value)) def func3(self): logging.info("Программа зевершена") class WorkThread(QtCore.QThread): ''' Потоковая задача ''' threadSignal = QtCore.pyqtSignal(int) finishSignal = QtCore.pyqtSignal() # +++ def __init__(self): super().__init__() def run(self): for i in range(10): self.msleep(200) self.threadSignal.emit(i) self.finishSignal.emit() # +++ def main(): app = QtWidgets.QApplication(sys.argv) window = ExampleApp() window.show() app.exec_() if __name__ == '__main__': main()

четверг, 23 января 2020 г.

Вращение изображения в PyQt5

#python #python_3x #qt5 #pyqt5


Нужно открыть картинку и вращать ее по часовой стрелке по команде. Вот мой код, в
который нужно вставить данную фичу:

#!/usr/bin/python3
# -*- coding: utf-8 -*-

import sys
from PyQt5.QtWidgets import (QWidget, QInputDialog,
    QPushButton, QApplication, QTextEdit, QLabel, QLineEdit,QFrame )
from PyQt5.QtGui import QBrush, QPalette, QPixmap, QPainter, QPen, QImage
from PyQt5.QtCore import Qt, QTimer, QPointF, QRect
from PIL import Image


class Collector(QWidget):

    def __init__(self):
        super().__init__()
        self.timer = QTimer()
        self.timer.timeout.connect(self.process_timeout)
        self.timer.start(10)  # 50 -- период в милисекундах
        self.phi = 0
        self.lbl = QLabel(self)

    def process_timeout(self):
        if self.phi == 0:
            self.phi += 5
        elif self.phi == 5:
            self.phi -= 5
        self.update()
    def showInputTc_h(self):
        text, ok = QInputDialog.getText(self, "input Dialog", "Enter data:")
        if ok:
            self.textEdit_Tc_h.setText(str(text))

    def showInputTr(self):
        text, ok = QInputDialog.getText(self, "input Dialog", "Enter data:")
        if ok:
            self.textEdit_Tr.setText(str(text))

    def showInputTt(self):
        text_Tt, ok = QInputDialog.getText(self, "input Dialog", "Enter data:")
        if ok:
            self.textEdit_Tt.setText(str(text_Tt))

    def lable_text_button(self):
        Tt = QPushButton("Tt", self)
        Tt.move(480, 130)
        Tc_h = QPushButton("Tc-h", self)
        Tc_h.move(400, 10)
        Tr = QPushButton("Tr", self)
        Tr.move(900, 530)

        self.textEdit_Tt = QLineEdit(self)
        self.textEdit_Tt.setGeometry(QRect(100, 90, 81, 31))
        self.textEdit_Tt.setObjectName("textEdit")
        self.textEdit_Tt.move(400, 130)
        Tt.clicked.connect(self.showInputTt)

        self.textEdit_Tr = QLineEdit(self)
        self.textEdit_Tr.setGeometry(QRect(100, 90, 81, 31))
        self.textEdit_Tr.setObjectName("textEdit")
        self.textEdit_Tr.move(800, 530)
        Tr.clicked.connect(self.showInputTr)

        self.textEdit_Tc_h = QLineEdit(self)
        self.textEdit_Tc_h.setGeometry(QRect(100, 90, 81, 31))
        self.textEdit_Tc_h.setObjectName("textEdit")
        self.textEdit_Tc_h.move(300, 10)
        Tc_h.clicked.connect(self.showInputTc_h)

    def get_image_size(self, img):
        im = Image.open(img)
        (width, height) = im.size
        return (width, height) # вернем ширину и висоту

    def draw_y(self, qp, x0, y0, range_int, const_y):
        for i in range(range_int):
            y0 -= 20 * i
            x1 = x0
            y1 = y0 + 10
            qp.drawLine(QPointF(x0, y0), QPointF(x1, y1))
            y0 = const_y

    def draw_x(self, qp, x0, y0, range_int, const_x):
        for i in range(range_int):
            x0 += 20 * i
            y1 = y0
            x1 = x0 + 10
            qp.drawLine(QPointF(x0, y0), QPointF(x1, y1))
            x0 = const_x

    def paintEvent(self, e):
        qp = QPainter()
        qp.begin(self)
        pen = QPen(Qt.red, 1)
        qp.translate(0, self.height())
        qp.scale(1, -1)
        qp.setPen(pen)
        pomp = QPixmap()
        QFrame.paintEvent(self, e)

        # width1 = 992,
        # height = 679
        list_y = [(292, 627, 12), (292, 320, 4), (485, 595, 2), (183, 183, 7), (465,
40, 3)]
        list_x = [(150, 637, 7), (310, 385, 6), (486, 607, 27), (183, 64, 14), (480,
64, 6), (690, 64, 16)]
        for y in list_y:
            self.draw_y(qp=qp, x0=y[0], y0=y[1]+self.phi, range_int=y[2], const_y=y[1]+self.phi)

        for x in list_x:
            self.draw_x(qp=qp, x0=x[0]+self.phi, y0=x[1], range_int=x[2], const_x=x[0]+self.phi)

        pen = QPen(Qt.blue, 1)
        qp.setPen(pen)
        list_y_cold = [(5, 627, 15), (240, 386, 3), (183, 317, 4), (296, 183, 2),
(485, 312, 3), (652, 562, 15)]
        list_x_cold = [(10, 347, 3), (113, 347, 3), (199, 347, 6), (345, 347, 4),
(296, 153, 37), (485, 272, 26), (656, 570, 18)]
        for y_cold in list_y_cold:

            self.draw_y(qp=qp, x0=y_cold[0], y0=y_cold[1]+self.phi, range_int=y_cold[2],
const_y=y_cold[1]+self.phi)

        for x_cold in list_x_cold:
            self.draw_x(qp=qp, x0=x_cold[0]+self.phi, y0=x_cold[1], range_int=x_cold[2],
const_x=x_cold[0]+self.phi)
        qp.end()

def main():
    app = QApplication(sys.argv)

    w = Collector()
    palette = QPalette()
    palette.setBrush(QPalette.Background,       QBrush(QPixmap("images/scheme.jpg")))
    size = w.get_image_size("images/scheme.jpg")
    w.setMaximumSize(size[0], size[1])
    w.setMinimumSize(size[0], size[1])
    w.setWindowTitle('Sun')
    w.setPalette(palette)
    w.lable_text_button()
    w.show()

    sys.exit(app.exec())

if __name__ == '__main__':
    main()

    


Ответы

Ответ 1



Чтобы вращать картинку, отображаемую с помощью QPixmap, можно QTransform().rotate() использовать. Код, основанный на ответе @Jean-Sébastien: #!/usr/bin/python3 """Usage: rotate-image """ from PyQt5.Qt import QImage, QLabel, QPixmap, QTransform, QWidget, Qt class ImageRotor(QWidget): def __init__(self, image_path, parent=None): super().__init__(parent) self.label = QLabel(self) self.image = QImage(image_path) # keep original image for rotation self.angle = 0 self.label.setAlignment(Qt.AlignCenter) # NOTE: keep image on screen pm = QPixmap(self.image) self.resize(pm.width(), pm.height()) # fit window to image self.label.setPixmap(pm) self.setWindowTitle('PyQt5 Image Rotor') def keyPressEvent(self, event): # on any key self.angle += 45 if event.key() == Qt.Key_Down else -45 t = QTransform().rotate(self.angle) self.label.setPixmap(QPixmap(self.image).transformed(t)) return super().keyPressEvent(event) if __name__ == '__main__': import sys from PyQt5.Qt import QApplication if len(sys.argv) < 2: # wrong arguments sys.exit(__doc__) # print usage app = QApplication(sys.argv) w = ImageRotor(sys.argv[1]) # center on screen w.move(app.desktop().screen().rect().center() - w.rect().center()) w.show() sys.exit(app.exec_()) При нажатии на любую клавишу, изображение, указанное в командной строке, вращается на 45 градусов. Если нажать на клавишу ↓ («вниз»), то по часовой стрелке вращение. начальный размер окна подгонятся под изображение используется выравнивание по центру, чтобы при повороте изображение не убегало сохраняется оригинальное изображение, чтобы повторные повороты не искажали бы картинку