I can't get to work a custom dialog made in Qt Designer. I understand how can i popup the dialog but i can't get the data from that line text.
main program.py
from PyQt5 import QtCore, QtGui, QtWidgets
from ui import Ui_MainWindow
from addui import Ui_Dialog as Form
from bs4 import BeautifulSoup
import requests
import time
import sys
class MainDialog(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self):
super(self.__class__, self).__init__()
self.setupUi(self)
self.actionRefresh.triggered.connect(self.refresh_btn)
self.actionAdd.triggered.connect(self.add_btn)
self.actionRemove.triggered.connect(self.remove_btn)
self.actionSettings.triggered.connect(self.settings_btn)
self.actionAbout.triggered.connect(self.about_btn)
self.actionExit.triggered.connect(self.exit_btn)
def open_dialog(self):
dialog = QtWidgets.QDialog()
dialog.ui = Form()
dialog.ui.setupUi(dialog)
dialog.exec_()
dialog.show()
def refresh_btn(self):
print('Refresh')
self.getting_data()
def add_btn(self):
print('Add')
self.open_dialog()
def remove_btn(self):
print('Remove')
def settings_btn(self):
print('Settings')
QtWidgets.QMessageBox.warning(self, 'Settings',
'Work in progress.\n'
' Coming soon!')
def about_btn(self):
print('About')
QtWidgets.QMessageBox.about(self, 'About Checking Prices',
'Checking Prices - Beta v1.0\n'
'\n'
'Copyright(c) 2015 - Pifu Valentin')
def exit_btn(self):
self.close()
def getting_data(self):
links = ['link1',
'link2',
'link3'
]
self.statusBar.showMessage('Getting data...')
try:
for nr, link in enumerate(links, start=1):
cont = requests.get(link)
soup = BeautifulSoup(cont.content, "html.parser")
title = soup.title.text[:40]
price = soup.find('span', {'itemprop': 'price'}).text
linetxt = ('{}. {} >> ${}').format(nr, title, price)
if nr == 1:
self.linetxt1.setText(linetxt)
elif nr == 2:
self.linetxt2.setText(linetxt)
elif nr == 3:
self.linetxt3.setText(linetxt)
self.statusBar.showMessage('Last updated - '+time.strftime('%H:%M:%S'))
except:
self.statusBar.showMessage('Error getting data.')
def main():
app = QtWidgets.QApplication(sys.argv)
form = MainDialog()
form.show()
app.exec_()
if __name__ == '__main__':
main()
addui.py (dialog)
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Dialog(object):
def setupUi(self, Dialog):
Dialog.setObjectName("Dialog")
Dialog.resize(200, 71)
Dialog.setMinimumSize(QtCore.QSize(200, 71))
Dialog.setMaximumSize(QtCore.QSize(200, 71))
Dialog.setContextMenuPolicy(QtCore.Qt.NoContextMenu)
icon = QtGui.QIcon()
icon.addPixmap(QtGui.QPixmap("Icons/Plus-32.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
Dialog.setWindowIcon(icon)
self.gridLayout = QtWidgets.QGridLayout(Dialog)
self.gridLayout.setObjectName("gridLayout")
self.text_link = QtWidgets.QLineEdit(Dialog)
self.text_link.setObjectName("text_link")
self.gridLayout.addWidget(self.text_link, 0, 0, 1, 2)
self.add_link = QtWidgets.QPushButton(Dialog)
self.add_link.setObjectName("add_link")
self.gridLayout.addWidget(self.add_link, 1, 0, 1, 1)
self.cancel_link = QtWidgets.QPushButton(Dialog)
self.cancel_link.setObjectName("cancel_link")
self.gridLayout.addWidget(self.cancel_link, 1, 1, 1, 1)
self.retranslateUi(Dialog)
self.cancel_link.clicked.connect(self.exit_dialog)
self.add_link.clicked.connect(self.get_link)
def retranslateUi(self, Dialog):
_translate = QtCore.QCoreApplication.translate
Dialog.setWindowTitle(_translate("Dialog", "Add link"))
self.add_link.setText(_translate("Dialog", "Add"))
self.cancel_link.setText(_translate("Dialog", "Cancel"))
def get_link(self):
print(self.text_link.text())
x = self.text_link.text()
return x
def exit_dialog(self):
self.destroy()
I have some problems with this program.
If i click on cancel to exit only the dialog not the main program. (i tried with self.close, self.hide...)
I want to add a link on that line_text and to get that link to the main program, but when i click on add to close dialog and data pass to the main program.
It's ok how i call the dialog ?
def open_dialog(self):
dialog = QtWidgets.QDialog()
dialog.ui = Form()
dialog.ui.setupUi(dialog)
dialog.exec_()
dialog.show()
Thanks. I don't get how i can do this, hope someone can help.
THanks again.
You need to exec_() to do this and Here is a minimal version of your code which is fixed
from PyQt4 import QtCore, QtGui
import sys
class PopUpDLG(QtGui.QDialog):
def __init__(self):
super(PopUpDLG, self).__init__()
self.setObjectName("self")
self.resize(200, 71)
self.setMinimumSize(QtCore.QSize(200, 71))
self.setMaximumSize(QtCore.QSize(200, 71))
self.setContextMenuPolicy(QtCore.Qt.NoContextMenu)
icon = QtGui.QIcon()
icon.addPixmap(QtGui.QPixmap("Icons/Plus-32.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.setWindowIcon(icon)
self.gridLayout = QtGui.QGridLayout(self)
self.gridLayout.setObjectName("gridLayout")
self.text_link = QtGui.QLineEdit(self)
self.text_link.setObjectName("text_link")
self.gridLayout.addWidget(self.text_link, 0, 0, 1, 2)
self.add_link = QtGui.QPushButton(self)
self.add_link.setObjectName("add_link")
self.gridLayout.addWidget(self.add_link, 1, 0, 1, 1)
self.cancel_link = QtGui.QPushButton(self)
self.cancel_link.setObjectName("cancel_link")
self.gridLayout.addWidget(self.cancel_link, 1, 1, 1, 1)
self.retranslateUi(self)
self.cancel_link.clicked.connect(self.reject)
self.add_link.clicked.connect(self.get_link)
self.retrunVal = None
def retranslateUi(self, Dialog):
_translate = QtCore.QCoreApplication.translate
self.setWindowTitle(_translate("Dialog", "Add link"))
self.add_link.setText(_translate("Dialog", "Add"))
self.cancel_link.setText(_translate("Dialog", "Cancel"))
def get_link(self):
self.retrunVal = self.text_link.text()
self.accept()
def exec_(self):
super(PopUpDLG, self).exec_()
return self.retrunVal
class MainDialog(QtGui.QMainWindow):
def __init__(self):
super(self.__class__, self).__init__()
centralwidget = QtGui.QWidget(self)
self.layout = QtGui.QHBoxLayout(centralwidget)
self.button = QtGui.QPushButton("Open")
self.valText = QtGui.QLabel("")
self.layout.addWidget(self.button)
self.layout.addWidget(self.valText)
self.setCentralWidget(centralwidget)
self.button.clicked.connect(self.open_dialog)
def open_dialog(self):
dialog = PopUpDLG()
value = dialog.exec_()
if value:
self.valText.setText(value)
def main():
app = QtGui.QApplication(sys.argv)
form = MainDialog()
form.show()
app.exec_()
if __name__ == '__main__':
main()
Related
I know this question has been asked in a couple ways but I cannot figure it out on my specific use case. I used QT designer (pyQT 5.15) to create a layout and would like to use vispy as the display. After reading it seemed I had to set a widget but it still isn't clear to me how. This is what I have, and I am trying to have the simple example of changing the color from black to white via a timer. There are no errors but there is no visualization either.
Here is the GUI.ui converted to Python called GUI.py
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Dialog(object):
def setupUi(self, Dialog):
Dialog.setObjectName("Dialog")
Dialog.resize(702, 603)
self.vispy_widget = QtWidgets.QWidget(Dialog)
self.vispy_widget.setGeometry(QtCore.QRect(150, 20, 531, 531))
self.vispy_widget.setObjectName("vispy_widget")
self.pushButton = QtWidgets.QPushButton(Dialog)
self.pushButton.setGeometry(QtCore.QRect(580, 560, 75, 23))
self.pushButton.setObjectName("pushButton")
self.horizontalScrollBar = QtWidgets.QScrollBar(Dialog)
self.horizontalScrollBar.setGeometry(QtCore.QRect(160, 560, 401, 20))
self.horizontalScrollBar.setOrientation(QtCore.Qt.Horizontal)
self.horizontalScrollBar.setObjectName("horizontalScrollBar")
self.horizontalSlider = QtWidgets.QSlider(Dialog)
self.horizontalSlider.setGeometry(QtCore.QRect(20, 60, 111, 16))
self.horizontalSlider.setOrientation(QtCore.Qt.Horizontal)
self.horizontalSlider.setObjectName("horizontalSlider")
self.hist_widget = QtWidgets.QWidget(Dialog)
self.hist_widget.setGeometry(QtCore.QRect(20, 90, 120, 80))
self.hist_widget.setObjectName("hist_widget")
self.retranslateUi(Dialog)
QtCore.QMetaObject.connectSlotsByName(Dialog)
def retranslateUi(self, Dialog):
_translate = QtCore.QCoreApplication.translate
Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
self.pushButton.setText(_translate("Dialog", "PushButton"))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
Dialog = QtWidgets.QDialog()
ui = Ui_Dialog()
ui.setupUi(Dialog)
Dialog.show()
sys.exit(app.exec_())
```
Here is the app part:
import sys
from vispy import gloo, app
from gui import Ui_Dialog
from PyQt5 import QtWidgets
app.use_app('pyqt5')
class Canvas(app.Canvas):
def __init__(self, *args, **kwargs):
app.Canvas.__init__(self, *args, **kwargs)
self._timer = app.Timer('auto', connect=self.on_timer, start=True)
self.tick = 0
def on_draw(self, event):
gloo.clear(color=True)
def on_timer(self, event):
self.tick += 1 / 60.0
c = abs(math.sin(self.tick))
gloo.set_clear_color((c, c, c, 1))
self.update()
class myWindow(QtWidgets.QMainWindow):
def __init__(self):
super(myWindow, self).__init__()
self.ui = Ui_Dialog()
self.ui.setupUi(self)
canvas = Canvas()
self.ui.vispy_widget(canvas.native)
if __name__ == "__main__":
gui = QtWidgets.QApplication(sys.argv)
Dialog = QtWidgets.QDialog()
ui = Ui_Dialog()
ui.setupUi(Dialog)
Dialog.show()
app.run()
#sys.exit(app.exec_())
There are the following errors:
The self.ui.vispy_widget(canvas.native) command does not make sense, the idea is to use vispy_widget as a container for the native vispy widget that can be placed through a layout.
The choice of the .ui form is used to determine the base class, in your case you should use QDialog instead of QMainWindow.
If you already set the Ui_Dialog in the widget then it is unnecessary to implement the same in if __name__ == "__main__":.
You must import the math module.
import math
import sys
from vispy import gloo, app
from PyQt5 import QtWidgets
from gui import Ui_Dialog
app.use_app("pyqt5")
class Canvas(app.Canvas):
def __init__(self, *args, **kwargs):
app.Canvas.__init__(self, *args, **kwargs)
self._timer = app.Timer("auto", connect=self.on_timer, start=True)
self.tick = 0
def on_draw(self, event):
gloo.clear(color=True)
def on_timer(self, event):
self.tick += 1 / 60.0
c = abs(math.sin(self.tick))
gloo.set_clear_color((c, c, c, 1))
self.update()
class MyWindow(QtWidgets.QDialog):
def __init__(self):
super(MyWindow, self).__init__()
self.ui = Ui_Dialog()
self.ui.setupUi(self)
self.canvas = Canvas()
lay = QtWidgets.QVBoxLayout(self.ui.vispy_widget)
lay.addWidget(self.canvas.native)
if __name__ == "__main__":
gui = QtWidgets.QApplication(sys.argv)
w = MyWindow()
w.show()
app.run()
Using PyQt5 with a QTableView, QStandardItemModel and QSortFilterProxy. After doing an insertRow on the model the Sort Proxy displays the data in the View Table in the correct sort order; however, I need to issue a view.selectRow on the record that was just inserted. Not sure how to do this if the ItemModel stores the data in unsorted order.
Similar but shorter example:
from PyQt5 import QtCore, QtWidgets
from PyQt5.QtCore import Qt, QSortFilterProxyModel
from PyQt5.QtGui import QStandardItemModel, QStandardItem
from PyQt5.QtWidgets import QWidget, QInputDialog
class Ui_Dialog(QWidget):
def setupUi(self, Dialog):
Dialog.setObjectName("Dialog")
Dialog.resize(282, 247)
self.tableView = QtWidgets.QTableView(Dialog)
self.tableView.setGeometry(QtCore.QRect(10, 10, 256, 192))
self.tableView.setObjectName("tableView")
self.tableModel = QStandardItemModel()
self.tableModel.setColumnCount(1)
self.tableModel.setHeaderData(0, Qt.Horizontal, "Category Name")
self.tableProxy = QSortFilterProxyModel()
self.tableProxy.setSourceModel(self.tableModel)
self.tableView.setModel(self.tableProxy)
self.tableProxy.setSortCaseSensitivity(Qt.CaseInsensitive)
self.pushButton = QtWidgets.QPushButton(Dialog)
self.pushButton.setGeometry(QtCore.QRect(90, 210, 87, 29))
self.pushButton.setObjectName("pushButton")
self.retranslateUi(Dialog)
QtCore.QMetaObject.connectSlotsByName(Dialog)
self.setup_connections()
self.load_data()
self.tableProxy.sort(0)
self.tableView.selectRow(0)
def retranslateUi(self, Dialog):
_translate = QtCore.QCoreApplication.translate
Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
self.pushButton.setText(_translate("Dialog", "New"))
def setup_connections(self):
self.pushButton.clicked.connect(self.add_record)
def load_data(self):
data = ('Alpha', 'Charlie', 'Foxtrot', 'Zulu', 'Bravo', 'Tango')
for ndx, val in enumerate(data):
print(ndx, val)
item = QStandardItem(val)
self.tableModel.insertRow(ndx, item)
def add_record(self):
i, ok = QInputDialog.getText(self, "Value Editor", "Emter A Value:")
if ok:
item = QStandardItem(i)
self.tableModel.insertRow(self.tableModel.rowCount(), item)
### NEED TO TRIGGER TABLE TO SELECT THE ROW JUST INSERTED ###
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
Dialog = QtWidgets.QDialog()
ui = Ui_Dialog()
ui.setupUi(Dialog)
Dialog.show()
sys.exit(app.exec_())
To select an item you must use the selectionModel() of the view, you have to pass the index of the model passed to the view, that is, the proxy, and the flag of the selection type. To obtain the index of the proxy you must first obtain the index of the sourceModel, for this you use indexFromItem() converting the QStandardItem to QModelIndex, and then use mapFromSource() to convert from the source to the proxy:
from PyQt5 import QtCore, QtGui, QtWidgets
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Widget, self).__init__(parent)
self.tableView = QtWidgets.QTableView()
self.tableModel = QtGui.QStandardItemModel()
self.tableModel.setColumnCount(1)
self.tableModel.setHeaderData(0, QtCore.Qt.Horizontal, "Category Name")
self.tableProxy = QtCore.QSortFilterProxyModel()
self.tableProxy.setSourceModel(self.tableModel)
self.tableView.setModel(self.tableProxy)
self.tableProxy.setSortCaseSensitivity(QtCore.Qt.CaseInsensitive)
self.pushButton = QtWidgets.QPushButton("New")
self.setup_connections()
self.load_data()
self.tableProxy.sort(0)
self.tableView.selectRow(0)
lay = QtWidgets.QVBoxLayout(self)
lay.addWidget(self.tableView)
lay.addWidget(self.pushButton)
def setup_connections(self):
self.pushButton.clicked.connect(self.add_record)
def load_data(self):
data = ('Alpha', 'Charlie', 'Foxtrot', 'Zulu', 'Bravo', 'Tango')
for ndx, val in enumerate(data):
item = QtGui.QStandardItem(val)
self.tableModel.insertRow(ndx, item)
#QtCore.pyqtSlot()
def add_record(self):
i, ok = QtWidgets.QInputDialog.getText(self, "Value Editor", "Emter A Value:")
if ok:
item = QtGui.QStandardItem(i)
self.tableModel.insertRow(self.tableModel.rowCount(), item)
ix = self.tableModel.indexFromItem(item)
ix_proxy = self.tableProxy.mapFromSource(ix)
self.tableView.selectionModel().select(ix_proxy, QtCore.QItemSelectionModel.ClearAndSelect)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())
I would like to put a cursor in a blank line edit box without having to click on it.
I looked through the Reference here
http://ftp.ics.uci.edu/pub/centos0/ics-custom-build/BUILD/PyQt-x11-gpl-4.7.2/doc/html/qlineedit.html#selectionStart
I tried calling
QLineEdit.home(True)
But this did not select the lineEdit so to say.
here is a watered down version of the code
from PyQt4 import QtCore, QtGui
import sys
import os
import os.path
class Ui_Form1(QtGui.QWidget):
def __init__(self):
QtGui.QWidget.__init__(self)
self.setupUi(self)
def setupUi(self, Form):
#init stuff
Form.setObjectName("Form")
Form.resize(794, 538)
self.gridLayout = QtGui.QGridLayout(Form)
self.gridLayout.setObjectName("gridLayout")
self.hLayout = QtGui.QHBoxLayout(Form)
self.hLayout.setObjectName("hLayout")
self.vLayout = QtGui.QVBoxLayout(Form)
self.vLayout.setObjectName("vLayout")
#label for information
self.gridLayout.addLayout(self.hLayout, 0, 0)
self.hLayout.addLayout(self.vLayout, 0)
self.label = QtGui.QLabel(Form)
self.label.setObjectName("label")
#label pixmap
self.label2 = QtGui.QLabel(Form)
self.label2.setObjectName("label")
#line edit
self.lineEdit = QtGui.QLineEdit(Form)
self.lineEdit.setAlignment(QtCore.Qt.AlignCenter)
self.gridLayout.addWidget(self.lineEdit, 3,0)
self.list = QtGui.QListWidget(self)
self.list.setObjectName("outlist")
self.list.setMinimumHeight(150)
self.vLayout.addWidget(self.list, 1)
self.hLayout.addWidget(self.label, 1)
self.vLayout.addWidget(self.label2, 0)
#self.hLayout.addWidget(self.label2, 0)
self.label2.setText('line edit')
self.retranslateUi(Form)
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
self.label.setAlignment(QtCore.Qt.AlignCenter)
self.label.setText('Picture would go here')
self.label2.setText('line edit')
self.list.addItem('cursor will disappear when this is pressed')
#press enter to update pic
#self.lineEdit.returnPressed.connect(self.update_pic)
#####sh
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
ex = Ui_Form1()
ex.show()
sys.exit(app.exec_())
self.lineEdit.setFocus(QtCore.Qt.StrongFocus)
In PyQt5:
self.lineEdit.setFocus()
I would like to get the folder pathes of a multiple selection. I wish to get only the ones that are highlighted when clicking. Ideally, a list would be updated interactively. I mean, if one folder is deselected, it is automatically removed from the list.
Here an example of QTreeView below ... Can you provide support please?
Thank you
from PyQt4 import QtCore, QtGui
class Ui_Dialog(object):
def setupUi(self, Dialog):
Dialog.resize(1150, 905)
self.gridLayout_2 = QtGui.QGridLayout(Dialog)
self.groupBox = QtGui.QGroupBox(Dialog)
self.gridLayout = QtGui.QGridLayout(self.groupBox)
self.treeView = QtGui.QTreeView(self.groupBox)
self.gridLayout.addWidget(self.treeView, 0, 0, 1, 1)
self.gridLayout_2.addWidget(self.groupBox, 0, 0, 1, 2)
self.fileSystemModel = QtGui.QFileSystemModel(self.treeView)
self.fileSystemModel.setFilter(QtCore.QDir.AllDirs | QtCore.QDir.NoDotAndDotDot | QtCore.QDir.AllEntries)
self.fileSystemModel.setReadOnly(True)
self.root = self.fileSystemModel.setRootPath('/home/')
self.treeView.setModel(self.fileSystemModel)
self.treeView.setRootIndex(self.root)
self.treeView.setSelectionMode(QtGui.QAbstractItemView.ContiguousSelection)
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
Dialog = QtGui.QDialog()
ui = Ui_Dialog()
ui.setupUi(Dialog)
Dialog.show()
sys.exit(app.exec_())
You can use the selectedIndexes() method of QItemSelectionModel.
from PyQt4 import QtCore, QtGui
class Ui_Dialog(object):
def setupUi(self, Dialog):
Dialog.resize(1150, 905)
self.gridLayout_2 = QtGui.QGridLayout(Dialog)
self.groupBox = QtGui.QGroupBox(Dialog)
self.gridLayout = QtGui.QGridLayout(self.groupBox)
self.treeView = QtGui.QTreeView(self.groupBox)
self.gridLayout.addWidget(self.treeView, 0, 0, 1, 1)
self.gridLayout_2.addWidget(self.groupBox, 0, 0, 1, 2)
self.fileSystemModel = QtGui.QFileSystemModel(self.treeView)
self.fileSystemModel.setFilter(QtCore.QDir.AllDirs |
QtCore.QDir.NoDotAndDotDot | QtCore.QDir.AllEntries)
self.fileSystemModel.setReadOnly(True)
self.root = self.fileSystemModel.setRootPath('/home/')
self.treeView.setModel(self.fileSystemModel)
self.treeView.setRootIndex(self.root)
self.treeView.setSelectionMode(QtGui.QAbstractItemView.ContiguousSelection)
self.treeView.selectionModel().selectionChanged.connect(self.getItems)
def getItems(self):
selected = self.treeView.selectionModel().selectedIndexes()
for index in selected:
if index.column() == 0:
print self.fileSystemModel.data(index,
self.fileSystemModel.FileNameRole).toString()
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
Dialog = QtGui.QDialog()
ui = Ui_Dialog()
ui.setupUi(Dialog)
Dialog.show()
sys.exit(app.exec_())
I followed this example (PyQT4) to create a "custom widget" in PyQT5 and ended up with following code:
progress.py
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import (QApplication,QMainWindow)
class Ui_Form(QMainWindow):
def __init__(self, name, parent=None):
super(Ui_Form,self).__init__(parent)
#Form.setObjectName("Form")
self.resize(619, 202)
self.formLayoutWidget = QtWidgets.QWidget()
self.formLayoutWidget.setGeometry(QtCore.QRect(0, 0, 621, 201))
self.formLayoutWidget.setObjectName("formLayoutWidget")
self.formLayout = QtWidgets.QFormLayout(self.formLayoutWidget)
self.formLayout.setContentsMargins(0, 0, 0, 0)
self.formLayout.setObjectName("formLayout")
self.progressBar = QtWidgets.QProgressBar(self.formLayoutWidget)
self.progressBar.setProperty("value", 24)
self.progressBar.setObjectName("progressBar")
self.formLayout.setWidget(2, QtWidgets.QFormLayout.SpanningRole, self.progressBar)
self.graphicsView = QtWidgets.QGraphicsView(self.formLayoutWidget)
self.graphicsView.setObjectName("graphicsView")
self.formLayout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.graphicsView)
self.label_Title = QtWidgets.QLabel(self.formLayoutWidget)
font = QtGui.QFont()
font.setFamily("Verdana")
font.setPointSize(22)
font.setBold(True)
font.setWeight(75)
self.label_Title.setFont(font)
self.label_Title.setObjectName("label_Title")
self.formLayout.setWidget(0, QtWidgets.QFormLayout.SpanningRole, self.label_Title)
self.timer = QtCore.QBasicTimer()
self.step = 0
self.timer.start(100,self)
self.retranslateUi()
QtCore.QMetaObject.connectSlotsByName(self)
def timerEvent(self, e):
if self.step>= 100:
self.timer.stop()
return
self.step = self.step + 1
self.progressBar.setValue(self.step)
def retranslateUi(self):
_translate = QtCore.QCoreApplication.translate
self.setWindowTitle(_translate("Form", "Form"))
self.label_Title.setText(_translate("Form", "TextLabel"))
new_ui.py
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(742, 538)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.pushButton_Start = QtWidgets.QPushButton(self.centralwidget)
self.pushButton_Start.setGeometry(QtCore.QRect(630, 20, 91, 31))
self.pushButton_Start.setObjectName("pushButton_Start")
self.lineEdit_URL = QtWidgets.QLineEdit(self.centralwidget)
self.lineEdit_URL.setGeometry(QtCore.QRect(20, 20, 601, 31))
self.lineEdit_URL.setObjectName("lineEdit_URL")
self.label = QtWidgets.QLabel(self.centralwidget)
self.label.setGeometry(QtCore.QRect(20, 460, 46, 13))
self.label.setObjectName("label")
self.label_status = QtWidgets.QLabel(self.centralwidget)
self.label_status.setGeometry(QtCore.QRect(73, 460, 651, 16))
self.label_status.setObjectName("label_status")
self.listWidget = QtWidgets.QListWidget(self.centralwidget)
self.listWidget.setGeometry(QtCore.QRect(20, 60, 701, 391))
self.listWidget.setObjectName("listWidget")
#MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 742, 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", "My Downloader"))
self.pushButton_Start.setText(_translate("MainWindow", "Start"))
self.label.setText(_translate("MainWindow", "Status :"))
self.label_status.setText(_translate("MainWindow", "Ideal..."))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
main.py
import sys
import threading
import logging
from PyQt5 import QtCore, QtGui, QtWidgets
import json
import urllib.request
from new_ui import Ui_MainWindow
import progress
import random
class MyForm(QtWidgets.QDialog):
def __init__(self, parent=None):
super(MyForm, self).__init__(parent)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.ui.pushButton_Start.clicked.connect(self.thread_start)
def thread_start(self):
p = threading.Thread(name='worker', target=self.start_download)
#Do UI updates
self.ui.label_status.setText('Fetching information...')
#self.listWidget.addItem(prgstr)
p.start()
def start_download(self):
............
code to fetch information from web
............
#itm = self.ui.listWidget.addItem(json_data['entries'][0]['title'])
self.ui.label_status.setText(json_data['entries'][0]['title'])
item = QtWidgets.QListWidgetItem(self.ui.listWidget)
item_widget = progress.Ui_Form("It works")
item.setSizeHint(item_widget.sizeHint())
self.ui.listWidget.addItem(item)
self.ui.listWidget.setItemWidget(item,item_widget)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
myapp = MyForm()
myapp.show()
sys.exit(app.exec_())
The above runs without any errors, but the following code fails to add any list item (custom widget), the label_status gets correctly populated with retrieved data - what am I missing here?
self.ui.label_status.setText(json_data['entries'][0]['title'])
item = QtWidgets.QListWidgetItem(self.ui.listWidget)
item_widget = progress.Ui_Form("It works")
item.setSizeHint(item_widget.sizeHint())
self.ui.listWidget.addItem(item)
self.ui.listWidget.setItemWidget(item,item_widget)
You should only ever update GUI elements from within the main GUI thread.
The worker thread should emit a signal when it's done, or perhaps do so periodically so that pending GUI events can be processed (i.e. by calling qApp.processEvents()).
If the worker thread generates data, use a Queue so that it can be accessed safely from the main thread.
UPDATE:
Here is a basic example (python3 only) of how to use QThread with a worker object. All communication between the GUI thread and the worker thread is done using signals and slots (see "Signals and Slots Across Threads" in the Qt docs for more on this).
import urllib.request
from PyQt4 import QtCore, QtGui
class Worker(QtCore.QObject):
finished = QtCore.pyqtSignal()
error = QtCore.pyqtSignal(object)
dataReady = QtCore.pyqtSignal(object)
#QtCore.pyqtSlot(str)
def process(self, url):
try:
response = urllib.request.urlopen(url, timeout=20)
try:
self.dataReady.emit(response.read())
finally:
response.close()
except urllib.error.URLError as exception:
self.error.emit(exception.reason)
except BaseException as exception:
self.error.emit(str(exception))
finally:
self.finished.emit()
class Window(QtGui.QWidget):
downloadRequest = QtCore.pyqtSignal(str)
def __init__(self):
QtGui.QWidget.__init__(self)
self.viewer = QtGui.QPlainTextEdit(self)
self.edit = QtGui.QLineEdit(self)
self.edit.setFocus()
self.button = QtGui.QPushButton('Download', self)
self.button.clicked.connect(self.handleButton)
layout = QtGui.QVBoxLayout(self)
layout.addWidget(self.viewer)
layout.addWidget(self.edit)
layout.addWidget(self.button)
# worker must not have a parent
self._worker = Worker()
self._thread = QtCore.QThread(self)
self._worker.moveToThread(self._thread)
self._worker.finished.connect(self._thread.quit)
self._worker.error.connect(self.handleError)
self._worker.dataReady.connect(self.handleDataReady)
self.downloadRequest.connect(self._worker.process)
def handleButton(self):
url = self.edit.text().strip()
if url and not self._thread.isRunning():
self.viewer.clear()
self._thread.start()
# safely communicate with worker via signal
self.downloadRequest.emit(url)
def handleError(self, reason):
self.viewer.clear()
print('ERROR:', reason)
def handleDataReady(self, data):
self.viewer.setPlainText(data.decode('utf-8'))
def closeEvent(self, event):
if self._thread.isRunning():
# Qt will complain if thread is still
# running, so quit it before closing
self._thread.quit()
self._thread.wait()
QtGui.QWidget.closeEvent(self, event)
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
window = Window()
window.edit.setText('http://stackoverflow.com')
window.setGeometry(500, 300, 300, 300)
window.show()
sys.exit(app.exec_())