Почему не работает код с потоками?
Не работает код. Пишет ошибку: QObject::setParent: Cannot set parent, new parent is in a different thread. Я не могу понять в чем проблема. Помогите. Вот код:
Update
У меня задумка в том что когда я что-то копирую в буфер, в окне должна появится кнопка, на которой будет написан текст из буфера. Если я снова что-то новое поместил в буфер, тогда добавляется новая кнопка в окне.
Я хотел поток, который вовремя работы приложения проверял буфер и добавлял кнопки в окно. Может это как-то по другому сделать.
from PyQt5 import QtWidgets, QtCore
import pyperclip
class ProgressCopyThread(QtCore.QThread):
def __init__(self, MyWindow, parent = None):
super().__init__(MyWindow)
self.window = MyWindow
def run(self):
buttonlst = self.window.buttonlist
total = -1
while True:
info_copy = pyperclip.paste()
if info_copy not in buttonlst:
total += 1
buttonlst.append(QtWidgets.QPushButton(str(info_copy)))
self.window.formLayout.addRow(buttonlst[total])
class MyWindow(QtWidgets.QWidget):
def __init__(self, parent = None):
QtWidgets.QWidget.__init__(self, parent)
self.resize(400, 150)
self.formLayout = QtWidgets.QFormLayout()
self.groupBox = QtWidgets.QGroupBox()
self.buttonlist = []
ProgressCopyThread(MyWindow = self).start()
self.groupBox.setLayout(self.formLayout)
scroll = QtWidgets.QScrollArea()
scroll.setWidget(self.groupBox)
scroll.setWidgetResizable(True)
scroll.setFixedHeight(150)
layout = QtWidgets.QVBoxLayout()
layout.addWidget(scroll)
self.setLayout(layout)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
window = MyWindow()
window.show()
sys.exit(app.exec_())
Ответы (2 шт):
Я не совсем понимаю что вы хотите сделать, но с потоками так не работают. То что показывается в окне делается только в основном потоке. Дополнительный поток нужен тогда, когда у вас есть тяжелая задача (длительные расчеты, загрузка данных и т.п.), которая заблокирует интерфейс если ее не делать в потоке. Если вас интересует работа с потоками, тогда полистайте посты, об этой теме уже много раз писали.
Т.к. я увидел что вы пишите о кнопках и у вас есть QFormLayout, появился такой пример.
from PyQt5 import QtWidgets, QtCore
'''
import pyperclip
class ProgressCopyThread(QtCore.QThread):
def __init__(self, MyWindow, parent = None):
super().__init__(MyWindow)
self.window = MyWindow
def run(self):
buttonlst = self.window.buttonlist
total = -1
while True:
info_copy = pyperclip.paste()
if info_copy not in buttonlst:
total += 1
buttonlst.append(QtWidgets.QPushButton(str(info_copy)))
self.window.formLayout.addRow(buttonlst[total])
'''
class MyWindow(QtWidgets.QWidget):
def __init__(self, parent = None):
QtWidgets.QWidget.__init__(self, parent)
self.resize(400, 150)
self.formLayout = QtWidgets.QFormLayout()
self.groupBox = QtWidgets.QGroupBox()
# self.buttonlist = []
for i in range(12):
lineEdit = QtWidgets.QLineEdit()
button = QtWidgets.QPushButton(f'Button {i}')
button.clicked.connect(lambda ch, l=lineEdit: print(l.text()))
self.formLayout.addRow(button, lineEdit)
# ProgressCopyThread(MyWindow = self).start()
self.groupBox.setLayout(self.formLayout)
scroll = QtWidgets.QScrollArea()
scroll.setWidget(self.groupBox)
scroll.setWidgetResizable(True)
scroll.setFixedHeight(150)
layout = QtWidgets.QVBoxLayout()
layout.addWidget(scroll)
self.setLayout(layout)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
window = MyWindow()
window.show()
sys.exit(app.exec_())
Update:
Тогда ваша задача может выглядеть так. Начинайте что-нибудь копировать и наблюдайте что происходит.
from PyQt5 import QtWidgets, QtCore
from PyQt5.QtWidgets import (QGridLayout, QPushButton, QTextEdit,
QApplication, QWidget)
from PyQt5.QtGui import QClipboard
class MyWindow(QtWidgets.QWidget):
def __init__(self, parent = None):
QtWidgets.QWidget.__init__(self, parent)
self.resize(400, 150)
self.formLayout = QtWidgets.QFormLayout()
self.groupBox = QtWidgets.QGroupBox()
self.groupBox.setLayout(self.formLayout)
scroll = QtWidgets.QScrollArea()
scroll.setWidget(self.groupBox)
scroll.setWidgetResizable(True)
scroll.setFixedHeight(150)
layout = QtWidgets.QVBoxLayout()
layout.addWidget(scroll)
self.setLayout(layout)
# Мы можем получить доступ к буферу, используя класс QClipboard.
# Затем мы можем вывести этот текст.
# Мы подключаем буфер обмена к методу, использующему строку:
QApplication.clipboard().dataChanged.connect(self.clipboardChanged)
self.i = 1
# Получить содержимое системного буфера обмена
def clipboardChanged(self):
# Затем мы захватываем содержимое, используя:
text = QApplication.clipboard().text()
lineEdit = QtWidgets.QLineEdit(text)
button = QtWidgets.QPushButton(f'Button {self.i}')
button.clicked.connect(lambda ch, l=lineEdit: print(l.text()))
self.formLayout.addRow(button, lineEdit)
self.i += 1
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
window = MyWindow()
window.show()
sys.exit(app.exec_())
Не пишу на Python QT, напишу на С++ QT, думаю все будет понятно.
Нет смысла создавать отдельный поток только ради того, чтобы проверять постоянно буфер. В QT есть класс QClipboard (документация) с его сигналом dataChanged. Снизу небольшой пример:
QClipboard *clipboard = QApplication::clipboard();
connect(clipboard, &QClipboard::dataChanged, this, [this, clipboard]()
{
// тут можно добавлять новые виджеты или что вы там собираетесь делать
qDebug() << clipboard->text();
});
Не могу проверить работает ли, но нашел тут (тут же стоит почитать про проблему з дубликацией сигнала) тот же код только для Python:
class MainWindow(QTableView):
def __init__(self, parent=None):
super().__init__(parent)
self.clipboard = QApplication.clipboard()
self.clipboard.dataChanged.connect(self.detectClipboardUrl)
@pyqtSlot()
def detectClipboardUrl(self):
print(self.clipboard.text())

