PyQt5 ile basit bir program yazdım. Çalışma olarak sonuç getiriyor ama sorguyu yaparken uygulama tamamen donuyor. Ben sorguyu yaparken program donmasın istiyorum. Bunu nasıl yapabilirim? Thread özelliğini araştırdım ama genelde hep "run "fonksiyonu üzerinden çalıştırmışlar bende yapmak istediğim işlemin fonksiyonunu “run” olarak adlandırınca çalışıyor ama ilerde birden fazla buton koyduğumda farklı farklı fonksiyonlara bağlamam gerekecek. Dolayısıyla bu sorunu nasıl aşarım ?
import sys
import requests
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import QThread
from PyQt5.QtWidgets import QMainWindow, QApplication
from bs4 import BeautifulSoup
#------------ ARAYÜZ --------------#
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(476, 391)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.pushButton = QtWidgets.QPushButton(self.centralwidget)
self.pushButton.setGeometry(QtCore.QRect(0, 270, 471, 81))
self.pushButton.setObjectName("pushButton")
self.lineEdit = QtWidgets.QLineEdit(self.centralwidget)
self.lineEdit.setGeometry(QtCore.QRect(0, 0, 471, 31))
self.lineEdit.setObjectName("lineEdit")
self.listWidget = QtWidgets.QListWidget(self.centralwidget)
self.listWidget.setGeometry(QtCore.QRect(0, 50, 471, 192))
self.listWidget.setObjectName("listWidget")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 476, 21))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
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", "GETİR"))
#--------- UYGULAMA --------#
class Worker(QThread):
def listele(self):
url = ui.lineEdit.text()
r = requests.get(url)
soup = BeautifulSoup(r.content)
linkler = soup.find_all("a")
for link in linkler:
baslik = link.get("title")
_translate = QtCore.QCoreApplication.translate
item = QtWidgets.QListWidgetItem()
font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(11)
item.setFont(font)
item.setCheckState(QtCore.Qt.Checked)
ui.listWidget.addItem(item)
item.setText(_translate("MainWindow", baslik))
#------------------------------------------------------------------#
Uygulama = QApplication(sys.argv)
menu = QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(menu)
menu.show()
ui.pushButton.clicked.connect(Worker.listele)
sys.exit(Uygulama.exec_())
Öncelikle hoşgeldiniz. Kodunuzu çalıştırdığım zaman arayüz halen donuyor. Sorunuza gelince, farklı butonların yapacağı işler tek bir run fonksiyonunda yer alamayacağı için her butona ait bir worker yazabilirsiniz. PyQt bilgim yok, aşağıdaki kodu normalden daha çok uzatmış olabilirim. İnternetten bulduğum bir örneği düzenleyerek paylaşıyorum.
import sys
import requests
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import QThread
from PyQt5.QtWidgets import QMainWindow, QApplication
from bs4 import BeautifulSoup
class Bs4Worker(QThread):
notifyProgress = QtCore.pyqtSignal(str)
def __init__(self, url, parent=None):
QThread.__init__(self, parent)
self.url = url
def run(self):
r = requests.get(self.url)
soup = BeautifulSoup(r.content)
linkler = soup.find_all("a")
for link in linkler:
baslik = link.get("title")
# ana sınıfa baslik bilgisini gönderiyor
self.notifyProgress.emit(baslik)
self.finished.emit()
#------------ ARAYÜZ --------------#
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(476, 391)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.pushButton = QtWidgets.QPushButton(self.centralwidget)
self.pushButton.setGeometry(QtCore.QRect(0, 270, 471, 81))
self.pushButton.setObjectName("pushButton")
self.lineEdit = QtWidgets.QLineEdit(self.centralwidget)
self.lineEdit.setGeometry(QtCore.QRect(0, 0, 471, 31))
self.lineEdit.setObjectName("lineEdit")
self.listWidget = QtWidgets.QListWidget(self.centralwidget)
self.listWidget.setGeometry(QtCore.QRect(0, 50, 471, 192))
self.listWidget.setObjectName("listWidget")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 476, 21))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
self.running = False
self.pushButton.clicked.connect(self.startBs4Worker)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.pushButton.setText(_translate("MainWindow", "GETİR"))
def reveiceData(self, data):
# Bu metot, thread tarafından gönderilen verileri
# işleyecek olan metottur
if data == None:
return
_translate = QtCore.QCoreApplication.translate
item = QtWidgets.QListWidgetItem()
font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(11)
item.setFont(font)
item.setCheckState(QtCore.Qt.Checked)
item.setText(_translate("MainWindow", data))
self.listWidget.addItem(item)
def setThreadStatus(self):
self.running = not self.running
def startBs4Worker(self):
if self.running:
print("Thread halen çalışıyor...")
return
else:
self.thread = QThread()
# Thread'in işleyeceği url adresini parametre olarak gönderiyoruz
self.worker = Bs4Worker(url=self.lineEdit.text())
self.worker.moveToThread(self.thread)
self.thread.started.connect(self.worker.run)
self.worker.finished.connect(self.thread.quit)
self.worker.finished.connect(self.worker.deleteLater)
self.worker.finished.connect(self.setThreadStatus)
self.thread.finished.connect(self.thread.deleteLater)
self.worker.notifyProgress.connect(self.reveiceData)
self.running = True
self.thread.start()
Uygulama = QApplication(sys.argv)
menu = QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(menu)
menu.show()
sys.exit(Uygulama.exec_())
kaynak: Use PyQt's QThread to Prevent Freezing GUIs – Real Python
2 Beğeni
Hocam çok teşekkür ederim. Tam olarak istediğim buydu, aslında farklı bir program üzerinde çalışıyorum bu sorunun çözülmesi demek orda ki sorunumun çözülmesi demek. Bu yüzden çok sağolun.
1 Beğeni
Hocam thread ile sorgu yaptırırken işlem tamamlanınca ekrana bir uyarı göstermek istiyorum. Bu örnek üzerinden konuşacak olursam sorgu bittikten sonra tüm içeriklerin listeye eklenmesi bitince “İşlem Tamam” uyarısı bastırıyorum ama program donuyor. Saatlerce araştırdım ama bir çözüm bulamadım bu konu hakkında bilginiz var mı acaba ?
Hocam ne tür bir deneme yaptığınızı ve nasıl bir hata aldığınızı görmeden bir şey söylemek zor. Ama mantık olarak yapmanız gereken run() fonksiyonunun sonuna bir bildirim eklemek veya self.worker.finished.connect(self.finishWorker)
ile bağlama yaparak finishWorker
metodunu yazmak.
Kodları aşağıya ekliyorum. Denediğim ve yaşadığım sorunları kodların yanında not olarak belirttim.
Amacım; bir sorgu yaptığımda sonuç başarılıysa Bilgi mesajı, başarısızsa Hata mesajı göstermek.
import sys
import requests
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import QThread
from PyQt5.QtWidgets import QMainWindow, QApplication, QMessageBox
from bs4 import BeautifulSoup
from time import sleep
# ------------ ARAYÜZ --------------#
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(476, 391)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.pushButton = QtWidgets.QPushButton(self.centralwidget)
self.pushButton.setGeometry(QtCore.QRect(0, 270, 471, 81))
self.pushButton.setObjectName("pushButton")
self.lineEdit = QtWidgets.QLineEdit(self.centralwidget)
self.lineEdit.setGeometry(QtCore.QRect(0, 0, 471, 31))
self.lineEdit.setObjectName("lineEdit")
self.listWidget = QtWidgets.QListWidget(self.centralwidget)
self.listWidget.setGeometry(QtCore.QRect(0, 50, 471, 192))
self.listWidget.setObjectName("listWidget")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 476, 21))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
self.running = False
self.pushButton.clicked.connect(self.startBs4Worker)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.pushButton.setText(_translate("MainWindow", "GETİR"))
def reveiceData(self, data):
# Bu metot, thread tarafından gönderilen verileri
# işleyecek olan metottur
if data == None:
return
_translate = QtCore.QCoreApplication.translate
item = QtWidgets.QListWidgetItem()
font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(11)
item.setFont(font)
item.setCheckState(QtCore.Qt.Checked)
item.setText(_translate("MainWindow", data))
self.listWidget.addItem(item)
def setThreadStatus(self):
self.running = not self.running
def startBs4Worker(self):
if self.running:
print("Thread halen çalışıyor...")
return
else:
self.thread = QThread()
# Thread'in işleyeceği url adresini parametre olarak gönderiyoruz
self.worker = Bs4Worker(url=self.lineEdit.text())
self.worker.moveToThread(self.thread)
self.thread.started.connect(self.worker.run)
self.worker.finished.connect(self.thread.quit)
self.worker.finished.connect(self.worker.deleteLater)
self.worker.finished.connect(self.setThreadStatus)
self.thread.finished.connect(self.thread.deleteLater)
self.worker.notifyProgress.connect(self.reveiceData)
self.worker.finished.connect(self.uyariBox) #---> Burası aktifken istediğim gibi ama hatalı link girildiğinde Hata mesajını nasıl aktif edeceğimi çözemedim.
self.running = True
self.thread.start()
def uyariBox(self):
self.msg = QMessageBox()
self.msg.thread()
self.msg.setWindowTitle("Bilgi !")
self.msg.setText("Tüm Sonuçlar Getirildi")
self.msg.setIcon(QMessageBox.Information)
self.msg.exec_()
class Bs4Worker(QThread):
notifyProgress = QtCore.pyqtSignal(str)
def __init__(self, url, parent=None):
QThread.__init__(self, parent)
self.url = url
def run(self):
try:
r = requests.get(self.url)
soup = BeautifulSoup(r.content)
linkler = soup.find_all("a")
for link in linkler:
baslik = link.get("title")
# ana sınıfa baslik bilgisini gönderiyor
self.notifyProgress.emit(baslik)
self.finished.connect(ui.uyariBox) #---> Burayı aktif edince uyarı anlık olarak görünüp hemen yok oluyor
#---> ve uygulamada bir yere tıklanmıyor. (Uyarı mesajında tamam butonuna basılmadığı için)
self.finished.emit()
# self.finished.connect(ui.uyariBox) #----> Burayı aktif edince Uyarı görünmüyor.
except:
print("link hata")
self.finished.emit()
# Hata mesajını göstermek için yeni bir QMessageBox oluşturduğumda uygulama çöküyor.
Uygulama = QApplication(sys.argv)
menu = QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(menu)
menu.show()
sys.exit(Uygulama.exec_())
Bağlamayı yanlış yerde yapmışsınız. Bağlama işlemini tıpkı diğerleri gibi startBs4Worker
içinde yapmanız gerekiyor.
import sys
import requests
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import QThread
from PyQt5.QtWidgets import QMainWindow, QApplication, QMessageBox
from bs4 import BeautifulSoup
class Bs4Worker(QThread):
notifyProgress = QtCore.pyqtSignal(str)
def __init__(self, url, parent=None):
QThread.__init__(self, parent)
self.url = url
def run(self):
r = requests.get(self.url)
soup = BeautifulSoup(r.content)
linkler = soup.find_all("a")
for link in linkler:
baslik = link.get("title")
# ana sınıfa baslik bilgisini gönderiyor
self.notifyProgress.emit(baslik)
self.finished.emit()
#------------ ARAYÜZ --------------#
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(476, 391)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.pushButton = QtWidgets.QPushButton(self.centralwidget)
self.pushButton.setGeometry(QtCore.QRect(0, 270, 471, 81))
self.pushButton.setObjectName("pushButton")
self.lineEdit = QtWidgets.QLineEdit(self.centralwidget)
self.lineEdit.setGeometry(QtCore.QRect(0, 0, 471, 31))
self.lineEdit.setObjectName("lineEdit")
self.listWidget = QtWidgets.QListWidget(self.centralwidget)
self.listWidget.setGeometry(QtCore.QRect(0, 50, 471, 192))
self.listWidget.setObjectName("listWidget")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 476, 21))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
self.running = False
self.pushButton.clicked.connect(self.startBs4Worker)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.pushButton.setText(_translate("MainWindow", "GETİR"))
def reveiceData(self, data):
# Bu metot, thread tarafından gönderilen verileri
# işleyecek olan metottur
if data == None:
return
_translate = QtCore.QCoreApplication.translate
item = QtWidgets.QListWidgetItem()
font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(11)
item.setFont(font)
item.setCheckState(QtCore.Qt.Checked)
item.setText(_translate("MainWindow", data))
self.listWidget.addItem(item)
def setThreadStatus(self):
self.running = not self.running
def uyariBox(self):
self.msg = QMessageBox()
self.msg.thread()
self.msg.setWindowTitle("Bilgi !")
self.msg.setText("Tüm Sonuçlar Getirildi")
self.msg.setIcon(QMessageBox.Information)
self.msg.exec_()
def startBs4Worker(self):
if self.running:
print("Thread halen çalışıyor...")
return
else:
self.thread = QThread()
# Thread'in işleyeceği url adresini parametre olarak gönderiyoruz
self.worker = Bs4Worker(url=self.lineEdit.text())
self.worker.moveToThread(self.thread)
self.thread.started.connect(self.worker.run)
self.worker.finished.connect(self.thread.quit)
self.worker.finished.connect(self.worker.deleteLater)
self.worker.finished.connect(self.setThreadStatus)
# ---------->
# işte bağlamayı burada yaptık
self.worker.finished.connect(self.uyariBox)
self.thread.finished.connect(self.thread.deleteLater)
self.worker.notifyProgress.connect(self.reveiceData)
self.running = True
self.thread.start()
Uygulama = QApplication(sys.argv)
menu = QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(menu)
menu.show()
sys.exit(Uygulama.exec_())
hocam orada da denedim fakat ben hata yönetimini de kontrol etmek istiyorum. Yani hatalı bir link girildiğinde Bs4Worker
class ından run
fonksiyonuna girince except:
çalışacak . Bende istiyorum ki except:
çalıştığı zaman hata penceresi oluşturayım.
Hmm o zaman düzenlememiz gerekecek. Şöyle bir çözüm aklıma geldi. Ortada bir hata yok, sadece algoritma kurarken ve tanımlamalar yaparken eksiklik var. O yüzden biraz eksikliklerinizi tamamlamanızı tavsiye ederim. Bu da bu konuda paylaştığım son kod olsun
import sys
import requests
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import QThread
from PyQt5.QtWidgets import QMainWindow, QApplication, QMessageBox
from bs4 import BeautifulSoup
class Bs4Worker(QThread):
notifyProgress = QtCore.pyqtSignal(dict)
def __init__(self, url, parent=None):
QThread.__init__(self, parent)
self.url = url
def run(self):
try:
r = requests.get(self.url)
soup = BeautifulSoup(r.content)
linkler = soup.find_all("a")
for link in linkler:
baslik = link.get("title")
# ana sınıfa baslik bilgisini gönderiyor
self.notifyProgress.emit({
"type":"info",
"content":"baslik"
})
# ana sınıfa işlemlerin bittiğini haber veriyoruz
self.notifyProgress.emit({
"type":"finish",
"content":""
})
except Exception as e:
# ana sınıfa bir hata olduğunu bildiriyoruz
self.notifyProgress.emit({
"type":"error",
"content":str(e)
})
self.finished.emit()
#------------ ARAYÜZ --------------#
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(476, 391)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.pushButton = QtWidgets.QPushButton(self.centralwidget)
self.pushButton.setGeometry(QtCore.QRect(0, 270, 471, 81))
self.pushButton.setObjectName("pushButton")
self.lineEdit = QtWidgets.QLineEdit(self.centralwidget)
self.lineEdit.setGeometry(QtCore.QRect(0, 0, 471, 31))
self.lineEdit.setObjectName("lineEdit")
self.listWidget = QtWidgets.QListWidget(self.centralwidget)
self.listWidget.setGeometry(QtCore.QRect(0, 50, 471, 192))
self.listWidget.setObjectName("listWidget")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 476, 21))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
self.running = False
self.pushButton.clicked.connect(self.startBs4Worker)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.pushButton.setText(_translate("MainWindow", "GETİR"))
def receiveData(self, data):
# Bu metot, thread tarafından gönderilen verileri
# işleyecek olan metottur
if data == None:
return
if data["type"] == "info":
# baslik bilgisi geldi ise
_translate = QtCore.QCoreApplication.translate
item = QtWidgets.QListWidgetItem()
font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(11)
item.setFont(font)
item.setCheckState(QtCore.Qt.Checked)
item.setText(_translate("MainWindow", data["content"]))
self.listWidget.addItem(item)
elif data["type"] == "error":
# url işlenirken bir hata mı oldu?
self.notify("Hata", data["content"])
elif data["type"] == "finish":
# tüm işlemler başarı ile mi sonuçlandı
self.notify("Bilgi","Tüm işlemler bitti")
def setThreadStatus(self):
self.running = not self.running
def notify(self, title, content):
msg = QMessageBox()
msg.thread()
msg.setWindowTitle(title)
msg.setText(content)
msg.setIcon(QMessageBox.Information)
msg.exec_()
def startBs4Worker(self):
if self.running:
print("Thread halen çalışıyor...")
return
else:
self.thread = QThread()
# Thread'in işleyeceği url adresini parametre olarak gönderiyoruz
self.worker = Bs4Worker(url=self.lineEdit.text())
self.worker.moveToThread(self.thread)
self.thread.started.connect(self.worker.run)
self.worker.finished.connect(self.thread.quit)
self.worker.finished.connect(self.worker.deleteLater)
self.worker.finished.connect(self.setThreadStatus)
self.thread.finished.connect(self.thread.deleteLater)
self.worker.notifyProgress.connect(self.receiveData)
self.running = True
self.thread.start()
Uygulama = QApplication(sys.argv)
menu = QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(menu)
menu.show()
sys.exit(Uygulama.exec_())
2 Beğeni
Hocam çok teşekkür ediyorum. Tam istediğim gibi olmuş. Konu kapanmıştır. Başka konularda görüşmek dileğiyle.
1 Beğeni
Bu arada konsoldaki uyarı mesajını görmüşsünüzdür. BeautifulSoup nesnesi oluştururken BeautifulSoup(r.content)
değil BeautifulSoup(r.content, "html.parser")
kullanılmasını önermiş. Bu da aklımızda kalsın.
1 Beğeni
Farkettim hocam da bu mesele bu uygulama olmadığı için dert etmedim. Uğraştığım uygulama çok daha kompleks kodları buraya yazıp sizlere de vakit kaybettirmemek adına bu tasarımı yapıp, burdaki algoritma mantığını oraya uyguladım herşey bitti sorunsuz çalışıyor şimdi. Çok sağolun
1 Beğeni