Enable/Disable QTreeWidget from updating - python

Is it possible to enable/disable a QTreeWidget from updating?
I want to add rows to my tree and update it manually with a button. Obviously when i add a row to the TreeWidget it will be shown in the table. Is there a way to disable this so i can add like 100 rows and than update it once? If not is there a solution with a TreeView?
import sys
from PyQt5.QtCore import QSize
from PyQt5.QtWidgets import QApplication, QMainWindow, QToolBar, QAction, QTreeWidget, QTreeWidgetItem
class Table(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
self.resize(800, 600)
self.setMinimumSize(QSize(800, 600))
self.table = QTreeWidget()
self.table.setHeaderLabels(["Description", "Price"])
self.setCentralWidget(self.table)
self.car = QTreeWidgetItem(["Car"])
self.house = QTreeWidgetItem(["House"])
self.table.addTopLevelItem(self.car)
self.table.addTopLevelItem(self.house)
toolbar = QToolBar("Toolbar")
carAction = QAction("Car", self)
carAction.triggered.connect(self.addToCar)
houseAction = QAction("House", self)
houseAction.triggered.connect(self.addToHouse)
updateAction = QAction("Update", self)
updateAction.triggered.connect(self.update)
toolbar.addAction(carAction)
toolbar.addAction(houseAction)
toolbar.addAction(updateAction)
self.addToolBar(toolbar)
def addToCar(self):
child = QTreeWidgetItem(["Audi", str(25000)])
self.car.addChild(child)
def addToHouse(self):
child = QTreeWidgetItem(["Villa", str(500000)])
self.house.addChild(child)
def update(self):
pass
if __name__ == "__main__":
app = QApplication(sys.argv)
win = Table()
win.show()
sys.exit( app.exec_() )

I do not know of a way to "suspend" tree updates, but what about using lists to store the children until one decides to update? See the modified example below (modifications are commented):
import sys
from PyQt5.QtCore import QSize
from PyQt5.QtWidgets import QApplication, QMainWindow, QToolBar, QAction, QTreeWidget, QTreeWidgetItem
class Table(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
self.resize(800, 600)
self.setMinimumSize(QSize(800, 600))
self.table = QTreeWidget()
self.table.setHeaderLabels(["Description", "Price"])
self.setCentralWidget(self.table)
self.car = QTreeWidgetItem(["Car"])
self.house = QTreeWidgetItem(["House"])
self.table.addTopLevelItem(self.car)
self.table.addTopLevelItem(self.house)
# initialize empty lists which will keep track of generated children
self.car_list, self.house_list = [], []
toolbar = QToolBar("Toolbar")
carAction = QAction("Car", self)
carAction.triggered.connect(self.addToCar)
houseAction = QAction("House", self)
houseAction.triggered.connect(self.addToHouse)
updateAction = QAction("Update", self)
updateAction.triggered.connect(self.update)
toolbar.addAction(carAction)
toolbar.addAction(houseAction)
toolbar.addAction(updateAction)
self.addToolBar(toolbar)
def addToCar(self):
child = QTreeWidgetItem(["Audi", str(25000)])
# instead of adding them directly to the tree, keep them in the list
self.car_list.append(child)
def addToHouse(self):
child = QTreeWidgetItem(["Villa", str(500000)])
# instead of adding them directly to the tree, keep them in the list
self.house.addChild(child)
def update(self):
# update the tree and reset the lists
self.car.addChildren(self.car_list)
self.house.addChildren(self.house_list)
self.car_list, self.house_list = [], []
if __name__ == "__main__":
app = QApplication(sys.argv)
win = Table()
win.show()
sys.exit( app.exec_() )

Related

PyQt5 POO Call instance of Class in another class

I would like when I click on a buttom from a toolbar created with PyQt get the selected items in a QListWidget created in other class (LisWorkDirectory class).
In the ToolBar.py in the compilation_ function, I would like to get all selected items. I want to get the instance of the ListWorkDirectory class to get the QListWidget that I created the first time I have launched my app.
If I instanciate ListWorkDirectory, I get a new instance, and the selectedItems return a empty list, it is a normal behaviour.
Maybe my architecture is not correct, so if you have any suggestion or remarks don't' hesitate to learn me.
Below my code so that you understand my request :
main.py
from MainWindow import MainWindow
from MenuBar import MenuBar
from ToolBar import ToolBar
from PyQt5.QtWidgets import QApplication
import sys
app = QApplication(sys.argv)
#Window
windowApp = MainWindow("pyCompile")
#MenuBar
menuBar = MenuBar()
#ToolBar
toolBar = ToolBar()
windowApp.setMenuBar(menuBar)
windowApp.addToolBar(toolBar)
windowApp.show()
sys.exit(app.exec_())
MainWindow.py
from PyQt5.QtWidgets import QMainWindow, QWidget, QLineEdit, QPushButton, QListWidget,QListWidgetItem,QPlainTextEdit, QFileDialog, QStatusBar ,QVBoxLayout, QHBoxLayout
from PyQt5.QtGui import QIcon
from PyQt5.QtCore import Qt
from ListWorkDirectory import ListWorkDirectory
from Logger import MyDialog
import logging
import os
class MainWindow(QMainWindow):
def __init__(self, windowTitle):
super().__init__()
#Logger
self.logger = MyDialog()
logging.info("pyCompile version 0.1")
self.setGeometry(150,250,600,350)
self.setWindowTitle(windowTitle)
self.workDirectoryField = QLineEdit()
self.workDirectoryField.setPlaceholderText("Select your work directory ...")
self.workDirectoryField.setText("F:/WORKSPACE/Projects")
self.workDirectoryButton = QPushButton()
self.workDirectoryButton.setIcon(QIcon(":folder.svg"))
self.workDirectoryButton.clicked.connect(self.launchDialog)
self.hBoxLayout = QHBoxLayout()
self.hBoxLayout.addWidget(self.workDirectoryField)
self.hBoxLayout.addWidget(self.workDirectoryButton)
#List folder in work directory
self.myListFolder = ListWorkDirectory()
print(self.myListFolder)
self.workDirectoryField.textChanged[str].connect(self.myListFolder.update)
self.hBoxLayoutLogger = QHBoxLayout()
self.hBoxLayoutLogger.addWidget(self.myListFolder)
self.hBoxLayoutLogger2 = QHBoxLayout()
self.hBoxLayoutLogger2.addWidget(self.logger)
self.centralWidget = QWidget(self)
self.setCentralWidget(self.centralWidget)
self.vBoxLayout = QVBoxLayout(self.centralWidget)
self.vBoxLayout.addLayout(self.hBoxLayout)
self.vBoxLayout.addLayout(self.hBoxLayoutLogger)
self.vBoxLayout.addLayout(self.hBoxLayoutLogger2)
#Status Bar
self.statusBar = QStatusBar()
self.statusBar.showMessage("Welcome in pyCompile", 5000)
self.setStatusBar(self.statusBar)
def launchDialog(self):
workDirectory = QFileDialog.getExistingDirectory(self, caption="Select work directory")
print(workDirectory)
self.workDirectoryField.setText(workDirectory)
MenuBar.py
from PyQt5.QtWidgets import QMenuBar
class MenuBar(QMenuBar):
def __init__(self):
super().__init__()
self.fileMenu = "&File"
self.editMenu = "&Edit"
self.helpMenu = "&Help"
self.initUI()
def initUI(self):
self.addMenu(self.fileMenu)
self.addMenu(self.editMenu)
self.addMenu(self.helpMenu)
ToolBar.py
from PyQt5.QtWidgets import QMainWindow, QToolBar, QAction
from PyQt5.QtGui import QIcon
import qrc_resources
from ListWorkDirectory import ListWorkDirectory
class ToolBar(QToolBar, ListWorkDirectory):
def __init__(self):
super().__init__()
self._createActions()
self.initUI()
def initUI(self):
self.setMovable(False)
self.addAction(self.compileAction)
self.addAction(self.settingsAction)
self.addAction(self.quitAction)
def _createActions(self):
self.compileAction = QAction(self)
self.compileAction.setStatusTip("Launch compilation")
self.compileAction.setText("&Compile")
self.compileAction.setIcon(QIcon(":compile.svg"))
self.compileAction.triggered.connect(self.compilation_)
self.settingsAction = QAction(self)
self.settingsAction.setText("&Settings")
self.settingsAction.setIcon(QIcon(":settings.svg"))
self.quitAction = QAction(self)
self.quitAction.setText("&Quit")
self.quitAction.setIcon(QIcon(":quit.svg"))
def compilation_(self):
"""
Get the instance of ListWorkDirectory to get selected items and launch the
compilation
"""
ListWorkDirectory.py
from PyQt5.QtWidgets import QListWidget,QListWidgetItem
from PyQt5.QtCore import Qt, QDir
import os
class ListWorkDirectory(QListWidget):
def __init__(self):
super().__init__()
self.clear()
def update(self, workDirectoryField):
isPathCorrect = self.checkPath(workDirectoryField)
if(isPathCorrect):
listOfDirectory = self.getFolderList(workDirectoryField, os.listdir(workDirectoryField))
for folder in listOfDirectory:
self.item = QListWidgetItem(folder)
self.item.setCheckState(Qt.Unchecked)
self.addItem(self.item)
else:
self.clear()
def checkPath(self, path):
QPath = QDir(path)
isQPathExist = QPath.exists()
isPathEmpty = self.isPathEmpty(path)
if(isQPathExist and not isPathEmpty):
return True
else:
return False
def getFolderList(self, path, listOfFiles):
listOfFolders=[]
for file_ in listOfFiles:
if(os.path.isdir(os.path.join(path, file_))):
listOfFolders.append(file_)
else:
pass
return listOfFolders
def isPathEmpty(self, path):
if(path != ""):
return False
else:
return True
Thank you for your help.
When you add widget to window (or to other widget) then this window (or widget) is its parent and you can use self.parent() to access element in window (or widget). When widgets are nested then you may even use self.parent().parent()
def compilation_(self):
"""
Get the instance of ListWorkDirectory to get selected items and launch the
compilation
"""
print(self.parent().myListFolder)
EDIT:
Class ListWorkDirectory has function item(number) to get item from list - but you overwrite it with line self.item = QListWidgetItem(folder). If you remove self. and use
item = QListWidgetItem(folder)
item.setCheckState(Qt.Unchecked)
self.addItem(item)
then this will show only checked items
def compilation_(self):
"""
Get the instance of ListWorkDirectory to get selected items and launch the
compilation
"""
lst = self.parent().myListFolder
for x in range(lst.count()):
item = lst.item(x)
#print(item.checkState(), item.text())
if item.checkState() :
print(item.text())
Full working code - everyone can simply copy all to one file and run it.
from PyQt5.QtWidgets import QMainWindow, QWidget, QLineEdit, QPushButton, QListWidget,QListWidgetItem,QPlainTextEdit, QFileDialog, QStatusBar ,QVBoxLayout, QHBoxLayout
from PyQt5.QtGui import QIcon
from PyQt5.QtCore import Qt
import logging
import os
# ---
from PyQt5.QtWidgets import QMenuBar
class MenuBar(QMenuBar):
def __init__(self):
super().__init__()
self.fileMenu = "&File"
self.editMenu = "&Edit"
self.helpMenu = "&Help"
self.initUI()
def initUI(self):
self.addMenu(self.fileMenu)
self.addMenu(self.editMenu)
self.addMenu(self.helpMenu)
# ---
from PyQt5.QtWidgets import QMainWindow, QToolBar, QAction
from PyQt5.QtGui import QIcon
class ToolBar(QToolBar):
def __init__(self):
super().__init__()
self._createActions()
self.initUI()
def initUI(self):
self.setMovable(False)
self.addAction(self.compileAction)
self.addAction(self.settingsAction)
self.addAction(self.quitAction)
def _createActions(self):
self.compileAction = QAction(self)
self.compileAction.setStatusTip("Launch compilation")
self.compileAction.setText("&Compile")
self.compileAction.setIcon(QIcon(":compile.svg"))
self.compileAction.triggered.connect(self.compilation_)
self.settingsAction = QAction(self)
self.settingsAction.setText("&Settings")
self.settingsAction.setIcon(QIcon(":settings.svg"))
self.quitAction = QAction(self)
self.quitAction.setText("&Quit")
self.quitAction.setIcon(QIcon(":quit.svg"))
def compilation_(self):
"""
Get the instance of ListWorkDirectory to get selected items and launch the
compilation
"""
lst = self.parent().myListFolder
for x in range(lst.count()):
item = lst.item(x)
#print(item.checkState(), item.text())
if item.checkState() :
print(item.text())
# ---
from PyQt5.QtWidgets import QListWidget, QListWidgetItem
from PyQt5.QtCore import Qt, QDir
import os
class ListWorkDirectory(QListWidget):
def __init__(self):
super().__init__()
self.clear()
def update(self, workDirectoryField):
isPathCorrect = self.checkPath(workDirectoryField)
if(isPathCorrect):
listOfDirectory = self.getFolderList(workDirectoryField, os.listdir(workDirectoryField))
for folder in listOfDirectory:
item = QListWidgetItem(folder)
item.setCheckState(Qt.Unchecked)
self.addItem(item)
else:
self.clear()
def checkPath(self, path):
QPath = QDir(path)
isQPathExist = QPath.exists()
isPathEmpty = self.isPathEmpty(path)
if(isQPathExist and not isPathEmpty):
return True
else:
return False
def getFolderList(self, path, listOfFiles):
listOfFolders=[]
for file_ in listOfFiles:
if(os.path.isdir(os.path.join(path, file_))):
listOfFolders.append(file_)
else:
pass
return listOfFolders
def isPathEmpty(self, path):
if(path != ""):
return False
else:
return True
class MainWindow(QMainWindow):
def __init__(self, windowTitle):
super().__init__()
#Logger
#self.logger = MyDialog()
logging.info("pyCompile version 0.1")
self.setGeometry(150,250,600,350)
self.setWindowTitle(windowTitle)
self.workDirectoryField = QLineEdit()
self.workDirectoryField.setPlaceholderText("Select your work directory ...")
self.workDirectoryField.setText("F:/WORKSPACE/Projects")
self.workDirectoryButton = QPushButton()
self.workDirectoryButton.setIcon(QIcon(":folder.svg"))
self.workDirectoryButton.clicked.connect(self.launchDialog)
self.hBoxLayout = QHBoxLayout()
self.hBoxLayout.addWidget(self.workDirectoryField)
self.hBoxLayout.addWidget(self.workDirectoryButton)
#List folder in work directory
self.myListFolder = ListWorkDirectory()
print(self.myListFolder)
self.workDirectoryField.textChanged[str].connect(self.myListFolder.update)
self.hBoxLayoutLogger = QHBoxLayout()
self.hBoxLayoutLogger.addWidget(self.myListFolder)
self.hBoxLayoutLogger2 = QHBoxLayout()
#self.hBoxLayoutLogger2.addWidget(self.logger)
self.centralWidget = QWidget(self)
self.setCentralWidget(self.centralWidget)
self.vBoxLayout = QVBoxLayout(self.centralWidget)
self.vBoxLayout.addLayout(self.hBoxLayout)
self.vBoxLayout.addLayout(self.hBoxLayoutLogger)
self.vBoxLayout.addLayout(self.hBoxLayoutLogger2)
#Status Bar
self.statusBar = QStatusBar()
self.statusBar.showMessage("Welcome in pyCompile", 5000)
self.setStatusBar(self.statusBar)
def launchDialog(self):
workDirectory = QFileDialog.getExistingDirectory(self, caption="Select work directory")
print(workDirectory)
self.workDirectoryField.setText(workDirectory)
# ---
from PyQt5.QtWidgets import QApplication
import sys
app = QApplication(sys.argv)
#Window
windowApp = MainWindow("pyCompile")
#MenuBar
menuBar = MenuBar()
#ToolBar
toolBar = ToolBar()
windowApp.setMenuBar(menuBar)
windowApp.addToolBar(toolBar)
windowApp.show()
sys.exit(app.exec_())

Remove gap during add layout

I am seeing gap into QVBoxLayout when I am placing layout it does not look good, any idea to fix issue
#!/usr/bin/env python
import os
import sys
from PySide2.QtCore import Qt, QSize, QRegExp, QFile, QTextStream
from PySide2.QtGui import QKeySequence, QTextCharFormat, QBrush,QColor, QTextDocument, QTextCursor
from PySide2.QtWidgets import (QApplication, QDesktopWidget, QMainWindow,
QPlainTextEdit, QGridLayout, QGroupBox,
QFormLayout, QHBoxLayout, QLabel, QLineEdit,
QMenu, QMenuBar, QPushButton, QMessageBox,
QTextEdit, QVBoxLayout, QWidget, QAction)
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.width = 1100
self.height = 700
self.set_main_window()
self.create_violation_text()
def set_main_window(self):
"""
Setting main window position
"""
self.setWindowTitle("GUI %s" %(os.path.abspath(__file__)))
self.setFixedSize(QSize(self.width, self.height))
wid = QDesktopWidget()
screen_width = wid.screen().frameGeometry().width()
screen_height = wid.screen().frameGeometry().height()
self.setGeometry(screen_width/2-self.width/2,
screen_height/2-self.height/2,
self.width, self.height)
def create_violation_text(self):
"""
creating main violation window which contain all violations
"""
self.plain_textedit = QPlainTextEdit()
self.plain_textedit.setLineWrapMode(QPlainTextEdit.NoWrap)
self.plain_textedit.setStyleSheet(
"""QPlainTextEdit {font-size: 14pt;
font-family: Courier;}""")
class ReviewWindow(MainWindow):
def __init__(self, waiver_files, app):
"""creating Review mode"""
super().__init__()
self.waiver_files = waiver_files
self.app = app
def create_widget(self):
self.create_text_finder()
self.create_violation_window()
#order matter
main_layout = QVBoxLayout()
main_layout.addWidget(self.text_finder)
main_layout.addWidget(self.create_violation_box)
#creating widgeth object as main window does not
#add layout directly it add only widget
window = QWidget()
window.setLayout(main_layout)
self.setCentralWidget(window)
def create_text_finder(self):
"""
create text finder which wil search string into document
"""
self.text_finder = QGroupBox()
layout = QHBoxLayout()
label = QLabel()
label.setText("Keyword:")
self.line_edit = QLineEdit()
self.line_edit.setText("Enter your search here")
push_button = QPushButton("Find")
push_button.clicked.connect(self.find_string_match)
layout.addWidget(label)
layout.addWidget(self.line_edit)
layout.addWidget(push_button)
self.text_finder.setLayout(layout)
def create_violation_window(self):
"""
creating violation window which contain text editor,
violation type and checkbox
"""
self.create_violation_box = QGroupBox()
layout = QGridLayout()
layout.addWidget(self.plain_textedit, 1, 0, 12, 1)
layout.setColumnMinimumWidth(0, 10)
self.create_violation_box.setLayout(layout)
def find_string_match(self):
"""
Adding string match operation
"""
#format for desire match
format = QTextCharFormat()
format.setBackground(QBrush(QColor("red")))
pattern = QRegExp(self.line_edit.text())
text_document = self.plain_textedit.document()
#Reverting if any
text_document.undo()
if pattern.isEmpty():
QMessageBox.warning("Search filed is empty")
else:
find_cursor = QTextCursor(text_document)
cursor = QTextCursor(text_document)
cursor.beginEditBlock()
while (not find_cursor.isNull() and not find_cursor.atEnd()):
found = False
find_cursor = text_document.find(pattern, find_cursor,
QTextDocument.FindWholeWords)
if (not find_cursor.isNull()):
found = True
find_cursor.movePosition(QTextCursor.WordRight,
QTextCursor.KeepAnchor)
find_cursor.mergeCharFormat(format)
cursor.endEditBlock()
if __name__ == '__main__':
app = QApplication(sys.argv)
cwd = os.path.dirname(__file__)
waiver_file = \[os.path.join(cwd, fdata) for fdata in os.listdir(cwd)\]
window = ReviewWindow(waiver_file, app)
window.create_widget()
window.show()
app.exec_()

How can I generate the buttons and connect them to different functions? [duplicate]

This question already has answers here:
How do I assert the identity of a PyQt5 signal?
(2 answers)
Closed 2 years ago.
I've created a search engine in PyQt5, using the code below:
import sys
from PyQt5.QtWidgets import (
QWidget, QLineEdit, QLabel, QScrollArea, QMainWindow,
QApplication, QHBoxLayout, QVBoxLayout, QSpacerItem, QSizePolicy, QCompleter, QPushButton
)
from PyQt5 import QtCore
from PyQt5.QtCore import Qt
tlist = ['thing1', 'thing2', 'thing3', 'thing4']
class Label(QWidget):
def __init__(self, name):
super(Label, self).__init__()
self.name = name
self.lbl = QLabel(self.name)
self.lbl.setTextInteractionFlags(QtCore.Qt.TextSelectableByMouse)
self.btn = QPushButton("Preview")
self.btn.setMaximumSize(QtCore.QSize(100,100))
self.btn.clicked.connect(self.printsignal)
self.hbox = QHBoxLayout()
self.hbox.addWidget(self.lbl)
self.hbox.addWidget(self.btn)
self.setLayout(self.hbox)
def show(self):
for labels in [self, self.lbl]:
labels.setVisible(True)
def hide(self):
for labels in [self, self.lbl]:
labels.setVisible(False)
def printsignal(self):
print("clicked")
class MainWindow(QMainWindow):
def __init__(self, *args, **kwargs):
super().__init__()
self.controls = QWidget()
self.controlsLayout = QVBoxLayout()
self.widgets = []
for name in tlist:
item = Label(name)
self.controlsLayout.addWidget(item)
self.widgets.append(item)
spacer = QSpacerItem(1, 1, QSizePolicy.Minimum, QSizePolicy.Expanding)
self.controlsLayout.addItem(spacer)
self.controls.setLayout(self.controlsLayout)
self.scroll = QScrollArea()
self.scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
self.scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.scroll.setWidgetResizable(True)
self.scroll.setWidget(self.controls)
self.searchbar = QLineEdit()
self.searchbar.textChanged.connect(self.update_display)
self.completer = QCompleter(tlist)
self.completer.setCaseSensitivity(Qt.CaseInsensitive)
self.searchbar.setCompleter(self.completer)
container = QWidget()
containerLayout = QVBoxLayout()
containerLayout.addWidget(self.searchbar)
containerLayout.addWidget(self.scroll)
container.setLayout(containerLayout)
self.setCentralWidget(container)
self.setGeometry(600, 100, 800, 600)
self.setWindowTitle('Search Engine')
def update_display(self, text):
for widget in self.widgets:
if text.lower() in widget.name.lower():
widget.show()
else:
widget.hide()
app = QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
The problem I have is, all the buttons share the same function and I don't know how to make them have different signals, as they are generated automatically. Basically, if I run the code it will show up like
this:
and when I press any of the buttons, it will print "clicked" (as in printsignal function). What I want is a different function for each button. Is there a way to do that?
Normally you can use self.sender().text() to get text from QButton which generated signal.
But because you create own widget Label with QButton and QLabel and you want text from label so you can get directly self.name
def printsignal(self):
print("clicked", self.name)
eventually self.lbl.text()
def printsignal(self):
print("clicked", self.lbl.text())
Working code.
I removed show(), hide() because you don't need it
import sys
from PyQt5.QtWidgets import (
QWidget, QLineEdit, QLabel, QScrollArea, QMainWindow,
QApplication, QHBoxLayout, QVBoxLayout, QSpacerItem, QSizePolicy, QCompleter, QPushButton
)
from PyQt5 import QtCore
from PyQt5.QtCore import Qt
tlist = ['thing1', 'thing2', 'thing3', 'thing4']
class Label(QWidget):
def __init__(self, name):
super().__init__()
self.name = name
self.lbl = QLabel(self.name)
self.lbl.setTextInteractionFlags(QtCore.Qt.TextSelectableByMouse)
self.btn = QPushButton("Preview")
self.btn.setMaximumSize(QtCore.QSize(100,100))
self.btn.clicked.connect(self.printsignal)
self.hbox = QHBoxLayout()
self.hbox.addWidget(self.lbl)
self.hbox.addWidget(self.btn)
self.setLayout(self.hbox)
def printsignal(self):
print("clicked", self.name)
class MainWindow(QMainWindow):
def __init__(self, *args, **kwargs):
super().__init__()
self.controls = QWidget()
self.controlsLayout = QVBoxLayout()
self.widgets = []
for name in tlist:
item = Label(name)
self.controlsLayout.addWidget(item)
self.widgets.append(item)
spacer = QSpacerItem(1, 1, QSizePolicy.Minimum, QSizePolicy.Expanding)
self.controlsLayout.addItem(spacer)
self.controls.setLayout(self.controlsLayout)
self.scroll = QScrollArea()
self.scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
self.scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.scroll.setWidgetResizable(True)
self.scroll.setWidget(self.controls)
self.searchbar = QLineEdit()
self.searchbar.textChanged.connect(self.update_display)
self.completer = QCompleter(tlist)
self.completer.setCaseSensitivity(Qt.CaseInsensitive)
self.searchbar.setCompleter(self.completer)
container = QWidget()
containerLayout = QVBoxLayout()
containerLayout.addWidget(self.searchbar)
containerLayout.addWidget(self.scroll)
container.setLayout(containerLayout)
self.setCentralWidget(container)
self.setGeometry(600, 100, 800, 600)
self.setWindowTitle('Search Engine')
def update_display(self, text):
for widget in self.widgets:
if text.lower() in widget.name.lower():
widget.show()
else:
widget.hide()
app = QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())

Implement QThread with QProgressBar in PySide (or PyQt) during calculation

I would like to know how to implement QProgressBar, which shows the progress of calculation in main thread.
Please refer to below codes.
import sys
from PySide2.QtWidgets import QApplication, QWidget, QPushButton, QVBoxLayout, QProgressBar
from PySide2.QtCore import QThread
class BarThread(QThread):
# Progress Bar UI Definition
def __init__(self):
QThread.__init__(self)
self.window = QWidget()
self.pgsb = QProgressBar()
self.lay = QVBoxLayout()
self.lay.addWidget(self.pgsb)
self.window.setLayout(self.lay)
self.isRun = False
# Thread Function Definition
def run(self):
self.window.show()
while self.isRun:
self.pgsb.setValue(self.percent)
print(self.percent)
if self.percent == 100:
self.isRun = False
class Tool(QWidget):
# Main UI Definition
def __init__(self):
windowWidth = 300
windowHeight = 300
QWidget.__init__(self)
self.setWindowTitle("Example")
self.resize(windowWidth, windowHeight)
self.bt = QPushButton('Numbering')
self.layout = QVBoxLayout()
self.layout.addWidget(self.bt)
self.setLayout(self.layout)
# Main Function Link Definition
self.bt.clicked.connect(self.numbering)
# Main Function Definition
def numbering(self):
bth = BarThread()
bth.start()
bth.isRun = True
for x in range(0,100000):
bth.percent = x/1000
print(x)
if __name__ == "__main__":
app = QApplication(sys.argv)
widget = Tool()
widget.show()
sys.exit(app.exec_())
You can copy and paste directly onto your python IDE.
(it needs PySide2. It can be installed with 'pip install pyside2' in your prompt).
This code executes simple numbering, however, this doesn't show numbering progress.
How can I solve this problem? Thank you in advance.
P.S. I'm using Windows 10 with PyCharm.
You have at least the following errors:
You must not modify the GUI from another thread, in your case the run method is executed in another thread but you try to modify the value of the QProgressBar, in addition to displaying a widget which is not allowed. If you want to modify the GUI with the information provided in the execution in the secondary thread you must do it through signals since they are thread-safe
The for loop is the blocking task so it must be executed in another thread.
Considering the above, the solution is:
import sys
from PySide2.QtWidgets import (
QApplication,
QWidget,
QPushButton,
QVBoxLayout,
QProgressBar,
)
from PySide2.QtCore import QThread, Signal
class ProgressWidget(QWidget):
def __init__(self, parent=None):
super(ProgressWidget, self).__init__(parent)
self.pgsb = QProgressBar()
lay = QVBoxLayout(self)
lay.addWidget(self.pgsb)
class BarThread(QThread):
progressChanged = Signal(int)
def run(self):
percent = 0
for x in range(0, 100000):
percent = x / 100
self.progressChanged.emit(percent)
class Tool(QWidget):
"""Main UI Definition"""
def __init__(self, parent=None):
super(Tool, self).__init__(parent)
self.setWindowTitle("Example")
self.resize(300, 300)
self.bt = QPushButton("Numbering")
layout = QVBoxLayout(self)
layout.addWidget(self.bt)
# Main Function Link Definition
self.bt.clicked.connect(self.numbering)
self.bar_thread = BarThread(self)
self.progress_widget = ProgressWidget()
self.bar_thread.progressChanged.connect(self.progress_widget.pgsb.setValue)
# Main Function Definition
def numbering(self):
self.bar_thread.start()
self.progress_widget.show()
def closeEvent(self, event):
super(Tool, self).closeEvent(event)
self.bar_thread.quit()
self.bar_thread.wait()
if __name__ == "__main__":
app = QApplication(sys.argv)
widget = Tool()
widget.show()
sys.exit(app.exec_())

When executing thread, the first execution fails in try statement

from PyQt5.QtWidgets import QMainWindow, QApplication,QLineEdit, QPushButton, QWidget, QAction, QTabWidget,QVBoxLayout
from PyQt5.QtCore import (QCoreApplication, QObject, QRunnable, QThread,
QThreadPool, pyqtSignal)
import sys
import os
from shutil import copy2
import _thread
import time
class AThread(QThread):
def run(self):
count = 0
while count < 5:
time.sleep(1)
print("A Increasing")
count += 1
class Example(QWidget):
def __init__(self):
super().__init__()
self.setAcceptDrops(True)
self.setWindowTitle('Learn')
self.setGeometry(300, 300, 300, 150)
self.layout = QVBoxLayout(self)
# Initialize tab screen
self.tabs = QTabWidget()
self.tab1 = QWidget()
self.tab2 = QWidget()
self.tabs.resize(300,200)
# Add tabs
self.tabs.addTab(self.tab1,"Tab 1")
self.tabs.addTab(self.tab2,"Tab 2")
# Create first tab
self.tab1.layout = QVBoxLayout(self)
self.pushButton1 = QPushButton("PyQt5 button")
self.pushButton1.clicked.connect(self.ON_PRESS)
self.textbox = QLineEdit(self)
self.tab1.layout.addWidget(self.textbox )
self.tab1.layout.addWidget(self.pushButton1)
self.tab1.setLayout(self.tab1.layout)
#Create Textbox inputs
# Add tabs to widget
self.layout.addWidget(self.tabs)
self.setLayout(self.layout)
def using_q_thread(self):
app = Example()
thread = AThread()
thread.start()
sys.exit(app.exec_())
def ON_PRESS(self):
###Here is the Issue
try:
self.using_q_thread()
except:
print ("Error: unable to start thread")
###Drag and Drop files to directory
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
ex.show()
Hoping I am asking this correctly, but whenever using QThread there appears to be a bit of a hiccup. the first attempt to access the threaded function causes the try statement to fail, but then it immediately works. Im just curious if this is part of the functionality or if there is any issue with my code.
Avoid using try-except as you see hidden the error, in my personal case I avoid using it as far as I can for this type of problems.
I do not see it necessary to create another Example within using_q_thread, another problem is that thread is a local variable that will be eliminated, so thread must be a member of the class for its scope to increase.
import sys
import time
from PyQt5.QtCore import QThread
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QTabWidget, QPushButton, QLineEdit
class AThread(QThread):
def run(self):
count = 0
while count < 5:
time.sleep(1)
print("A Increasing")
count += 1
class Example(QWidget):
def __init__(self):
super().__init__()
self.setAcceptDrops(True)
self.setWindowTitle('Learn')
self.setGeometry(300, 300, 300, 150)
self.layout = QVBoxLayout(self)
# Initialize tab screen
self.tabs = QTabWidget()
self.tab1 = QWidget()
self.tab2 = QWidget()
self.tabs.resize(300,200)
# Add tabs
self.tabs.addTab(self.tab1,"Tab 1")
self.tabs.addTab(self.tab2,"Tab 2")
# Create first tab
self.tab1.layout = QVBoxLayout()
self.pushButton1 = QPushButton("PyQt5 button")
self.pushButton1.clicked.connect(self.ON_PRESS)
self.textbox = QLineEdit(self)
self.tab1.layout.addWidget(self.textbox )
self.tab1.layout.addWidget(self.pushButton1)
self.tab1.setLayout(self.tab1.layout)
#Create Textbox inputs
# Add tabs to widget
self.layout.addWidget(self.tabs)
def using_q_thread(self):
self.thread = AThread()
self.thread.start()
def ON_PRESS(self):
self.using_q_thread()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
ex.show()
sys.exit(app.exec_())

Categories