PyQt5 POO Call instance of Class in another class - python

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_())

Related

PyQt5 "Ghost" of QIcon appears in QLineEdit of a QComboBox

I have a QComboBox and I want each item to have its own QIcon, but the QIcon should only be visible in the dropdown. I took an answer from a previous question and it works pretty well:
As you can see, the Icon only appears in the dropdown. The problem arises when I set the QComboBox to be editable and this happens:
Here a "ghost" of the QIcon is still there which in turn displaces the text.
My question is: What causes this and how can I remove this "ghost" so that the text appears normally?
My code:
from PyQt5.QtWidgets import (
QApplication,
QComboBox,
QHBoxLayout,
QStyle,
QStyleOptionComboBox,
QStylePainter,
QWidget,
)
from PyQt5.QtGui import QIcon, QPalette
from PyQt5.QtCore import QSize
class EditCombo(QComboBox):
def __init__(self, parent=None):
super(EditCombo, self).__init__(parent)
self.editable_index = 99
self.currentIndexChanged.connect(self.set_editable)
def setEditableAfterIndex(self, index):
self.editable_index = index
def set_editable(self, index: int) -> None:
if index >= self.editable_index:
self.setEditable(True)
else:
self.setEditable(False)
self.update()
def paintEvent(self, event):
painter = QStylePainter(self)
painter.setPen(self.palette().color(QPalette.Text))
opt = QStyleOptionComboBox()
self.initStyleOption(opt)
opt.currentIcon = QIcon()
opt.iconSize = QSize()
painter.drawComplexControl(QStyle.CC_ComboBox, opt)
painter.drawControl(QStyle.CE_ComboBoxLabel, opt)
class Example(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
hbox = QHBoxLayout()
edit_ico = QIcon("edit.png")
empty_ico = QIcon("empty.png") # For margin
combo = EditCombo(self)
combo.setEditableAfterIndex(2)
combo.addItem(empty_ico, "Foo 1")
combo.addItem(edit_ico, "Foo 2")
combo.addItem(edit_ico, "Bar 1")
combo.addItem(edit_ico, "Bar 2")
hbox.addWidget(combo)
self.setLayout(hbox)
self.show()
def main():
import sys
app = QApplication(sys.argv)
ex = Example()
ex.setFixedWidth(300)
sys.exit(app.exec_())
if __name__ == "__main__":
main()
QComboBox also uses the icon to set the position of the QLineEdit that is used when the QComboBox is editable so you see that displacement, if you don't want to observe that then you have to recalculate the geometry. The following code does it through a QProxyStyle:
class ProxyStyle(QProxyStyle):
def subControlRect(self, control, option, subControl, widget=None):
r = super().subControlRect(control, option, subControl, widget)
if control == QStyle.CC_ComboBox and subControl == QStyle.SC_ComboBoxEditField:
if widget.isEditable():
widget.lineEdit().setGeometry(r)
return r
class EditCombo(QComboBox):
def __init__(self, parent=None):
super(EditCombo, self).__init__(parent)
self._style = ProxyStyle(self.style())
self.setStyle(self._style)
self.editable_index = 99
self.currentIndexChanged.connect(self.set_editable)
# ...

Enable/Disable QTreeWidget from updating

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_() )

How do I create a print preview of QWebEngineView in PyQt5?

I'm trying to create a print preview of a QWebEngineView but I can't get it to work.
Here's my code:
...
self.view = QWebEngineView()
...
def handle_preview(self):
dialog = QPrintPreviewDialog()
dialog.paintRequested.connect(self.view.print_)
dialog.exec_()
The code gives me this error:
AttributeError: 'QWebEngineView' object has no attribute 'print_'
The code works perfectly when I use QTextEdit. But that's not what I want. I want to use QWebEngineView.
Based on the official example: WebEngine Widgets PrintMe Example you can implement the preview using the following code.
from PyQt5.QtCore import (QCoreApplication, QEventLoop, QObject, QPointF, Qt,
QUrl, pyqtSlot)
from PyQt5.QtGui import QKeySequence, QPainter
from PyQt5.QtPrintSupport import QPrintDialog, QPrinter, QPrintPreviewDialog
from PyQt5.QtWebEngineWidgets import QWebEnginePage, QWebEngineView
from PyQt5.QtWidgets import QApplication, QDialog, QLabel, QProgressBar, QProgressDialog, QShortcut
class PrintHandler(QObject):
def __init__(self, parent = None):
super().__init__(parent)
self.m_page = None
self.m_inPrintPreview = False
def setPage(self, page):
assert not self.m_page
self.m_page = page
self.m_page.printRequested.connect(self.printPreview)
#pyqtSlot()
def print(self):
printer = QPrinter(QPrinter.HighResolution)
dialog = QPrintDialog(printer, self.m_page.view())
if dialog.exec_() != QDialog.Accepted:
return
self.printDocument(printer)
#pyqtSlot()
def printPreview(self):
if not self.m_page:
return
if self.m_inPrintPreview:
return
self.m_inPrintPreview = True
printer = QPrinter()
preview = QPrintPreviewDialog(printer, self.m_page.view())
preview.paintRequested.connect(self.printDocument)
preview.exec()
self.m_inPrintPreview = False
#pyqtSlot(QPrinter)
def printDocument(self, printer):
loop = QEventLoop()
result = False
def printPreview(success):
nonlocal result
result = success
loop.quit()
progressbar = QProgressDialog(self.m_page.view())
progressbar.findChild(QProgressBar).setTextVisible(False)
progressbar.setLabelText("Wait please...")
progressbar.setRange(0, 0)
progressbar.show()
progressbar.canceled.connect(loop.quit)
self.m_page.print(printer, printPreview)
loop.exec_()
progressbar.close()
if not result:
painter = QPainter()
if painter.begin(printer):
font = painter.font()
font.setPixelSize(20)
painter.setFont(font)
painter.drawText(QPointF(10, 25), "Could not generate print preview.")
painter.end()
def main():
import sys
QCoreApplication.setAttribute(Qt.AA_EnableHighDpiScaling)
app = QApplication(sys.argv)
app.setApplicationName("Previewer")
view = QWebEngineView()
view.setUrl(QUrl("https://stackoverflow.com/questions/59438021"))
view.resize(1024, 750)
view.show()
handler = PrintHandler()
handler.setPage(view.page())
printPreviewShortCut = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_P), view)
printShortCut = QShortcut(QKeySequence(Qt.CTRL + Qt.SHIFT + Qt.Key_P), view)
printPreviewShortCut.activated.connect(handler.printPreview)
printShortCut.activated.connect(handler.print)
sys.exit(app.exec_())
if __name__ == "__main__":
main()
Note: For PySide2 you only have to change pyqtSlot to Slot.

Emit() a Signal to a different class isn't working

I am currently working on a GUI with PyQt5 (I'm a noob when it comes to python and Qt) and I need to emit a Signal from one class to another.
I read about this and googled around and also found a lot of helpful stuff but it still doesn't work for me.
This is my code-dummy:
Class Nr.1:
import sys
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
import Class2
class Class1(QWidget):
eventButtonPressed = pyqtSignal(str)
def __init__(self, parent=None):
super().__init__(parent)
self.Class1Btn = QPushButton('Button')
self.Class1Edit = QLineEdit(self)
self.Class1Btn.clicked.connect(self.clicked)
# Layout stuff to mimic my real program
self.Class1Grid = QGridLayout(self)
self.Class1Grid.addWidget(self.Class1Btn)
self.Class1Grid.addWidget(self.Class1Edit)
self.groupBoxLayout1 = QGroupBox(self)
self.groupBoxLayout1.setLayout(self.Class1Grid)
def clicked(self):
self.eventButtonPressed.emit(self.Class1Edit.text())
Class Nr.2:
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
import Class1
class Class2(QWidget):
def __init__(self):
super().__init__()
self.Class1OBJ = Class1.Class1(self)
self.Class1OBJ.eventButtonPressed.connect(self.StuffWhenSignalIsEmitted)
# Layout stuff to mimic my real program
self.Class2Edit = QLineEdit(self)
self.Class2Grid = QGridLayout(self)
self.Class2Grid.addWidget(self.Class2Edit)
self.groupBoxLayout2 = QGroupBox(self)
self.groupBoxLayout2.setLayout(self.Class2Grid)
def StuffWhenSignalIsEmitted(self, text):
print('Text from Class 2 Widget: {}'.format(self.Class2Edit))
print('Text from Class 1 Widget: {}'.format(text))
My Main Window:
import sys
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
import Class1
import Class2
class MainWindow(QWidget, QApplication):
def __init__(self):
super().__init__()
self.Class1OBJ = Class1.Class1()
self.Class2OBJ = Class2.Class2()
self.WinLayout = QVBoxLayout(self)
self.WinLayout.addWidget(self.Class1OBJ.groupBoxLayout1)
self.WinLayout.addWidget(self.Class2OBJ.groupBoxLayout2)
self.setGeometry(1100, 300, 300, 300)
self.setWindowTitle("GUI")
self.show()
app = QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
I want the program to print the statements from the StuffWhenSignalIsEmitted method when I press the button (if it is possible). So I want to print what is in the LineEdit from Class one, as well as what is in the LineEdit from Class2.
It seems that you think that if a variable has the same name in different classes it is the same variable, because they are not, they are different objects. The self.Class1OBJ in Class2 is different from the self.Class1OBJ in MainWindow.
So the solution is just to create a single self.Class1OBJ:
Class2.py
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
class Class2(QWidget):
def __init__(self):
super().__init__()
# Layout stuff to mimic my real program
self.Class2Edit = QLineEdit(self)
self.Class2Grid = QGridLayout(self)
self.Class2Grid.addWidget(self.Class2Edit)
self.groupBoxLayout2 = QGroupBox(self)
self.groupBoxLayout2.setLayout(self.Class2Grid)
def StuffWhenSignalIsEmitted(self, text):
print('Text from Class 2 Widget: {}'.format(self.Class2Edit))
print('Text from Class 1 Widget: {}'.format(text))
main.py
import sys
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
import Class1
import Class2
class MainWindow(QWidget, QApplication):
def __init__(self):
super().__init__()
self.Class1OBJ = Class1.Class1()
self.Class2OBJ = Class2.Class2()
# add the following line
self.Class1OBJ.eventButtonPressed.connect(self.Class2OBJ.StuffWhenSignalIsEmitted)
self.WinLayout = QVBoxLayout(self)
self.WinLayout.addWidget(self.Class1OBJ.groupBoxLayout1)
self.WinLayout.addWidget(self.Class2OBJ.groupBoxLayout2)
self.setGeometry(1100, 300, 300, 300)
self.setWindowTitle("GUI")
self.show()
app = QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
Try it:
import sys
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
class ClassTwo(QWidget):
def __init__(self):
super().__init__()
self.classOneOBJ = ClassOne(self) # + self
self.classOneOBJ.eventButtonPressed.connect(self.StuffWhenSignalIsEmitted)
layout = QGridLayout(self)
layout.addWidget(self.classOneOBJ)
def StuffWhenSignalIsEmitted(self, text):
print('it worked ->{}'.format(text))
# and do stuff with instance variables of an existing object
class ClassOne(QWidget):
eventButtonPressed = pyqtSignal(str)
def __init__(self, parent=None):
super().__init__(parent)
self.lineEdit = QLineEdit()
self.Btn = QPushButton('Button')
self.Btn.clicked.connect(self.clicked)
layout = QGridLayout(self)
layout.addWidget(self.lineEdit)
layout.addWidget(self.Btn)
def clicked(self):
self.eventButtonPressed.emit(self.lineEdit.text())
if __name__ == '__main__':
app = QApplication(sys.argv)
main = ClassTwo()
main.show()
sys.exit(app.exec_())

Open a file from main window to a new window in PyQt5 (in different files)

I have two files, one for my main window, which has one image and one button and one for a new window. What I want it to do is that when I push the button from my main window, it lets me load a file and show it in a TextEdit widget in the new window
so here I have the files I'm using:
MainWindow.py
import sys
import os
from PyQt5 import QtWidgets, QtGui
from PyQt5.QtWidgets import QApplication, QWidget
from PyQt5.QtWidgets import QPushButton, QVBoxLayout, QTextEdit, QHBoxLayout, QLabel, QMainWindow, QAction, QFileDialog
class Window(QWidget):
def __init__(self, parent=None):
super(Window, self).__init__(parent)
self.img = QLabel()
self.relleno=QLabel()
self.btn_load = QPushButton('Load')
self.width = 400
self.height = 150
self.init_ui()
def init_ui(self):
self.img.setPixmap(QtGui.QPixmap("someimage.png"))
h_layout = QHBoxLayout()
v_layout = QVBoxLayout()
h_final = QHBoxLayout()
h_layout.addWidget(self.img)
v_layout.addWidget(self.btn_load)
h_final.addLayout(h_layout)
h_final.addLayout(v_layout)
self.btn_load.clicked.connect(self.loadafile)
self.setLayout(h_final)
self.setWindowTitle('This is main window')
self.setGeometry(600,150,self.width,self.height)
self.show()
def loadafile(self):
filename = QFileDialog.getOpenFileName(self, 'Open File', os.getenv('HOME'))
with open(filename[0], 'r') as f:
file_text = f.read()
return file_text
def main():
app = QApplication(sys.argv)
main = Window()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
NewWindow.py
import os
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QTextEdit, QVBoxLayout
from MainWindow import loadafile
info=loadafile()
class SecondWindow(QWidget):
def __init__(self):
super(SecondWindow, self).__init__()
self.text = QTextEdit(self)
self.init_ui()
def init_ui(self):
v_layout = QVBoxLayout()
v_layout.addWidget(self.text)
self.setLayout(v_layout)
self.setText(info)
self.setWindowTitle('Opened Text')
self.show()
app = QApplication(sys.argv)
shower = SecondWindow()
sys.exit(app.exec_())
I think the loadafile does return my file_text variable but I don't know how to open the new window from there. I think I need to use a destructor for main window and then show the new window but I'm not sure of how to do this (This is the first time I try OOP)
A program is not a set of files, especially in OOP a program is the interactions of objects. And the objects interact if they have the same scope, so both windows must be created in one place so that the information from one pass to the other.
On the other hand in Qt there is a fundamental concept that is the signals, this functionality allows to notify the change of a state to another object without a lot of dependency, so in this case I will create a signal that transmits the text to the other object.
NewWindow.py
from PyQt5 import QtWidgets
class SecondWindow(QtWidgets.QWidget):
def __init__(self):
super(SecondWindow, self).__init__()
self.text = QtWidgets.QTextEdit(self)
self.init_ui()
def init_ui(self):
v_layout = QtWidgets.QVBoxLayout(self)
v_layout.addWidget(self.text)
self.setWindowTitle('Opened Text')
self.show()
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
shower = SecondWindow()
sys.exit(app.exec_())
MainWindow.py
import os
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from NewWindow import SecondWindow
class Window(QtWidgets.QWidget):
textChanged = QtCore.pyqtSignal(str)
def __init__(self, parent=None):
super(Window, self).__init__(parent)
self.img =QtWidgets.QLabel()
self.relleno=QtWidgets.QLabel()
self.btn_load = QtWidgets.QPushButton('Load')
self.width = 400
self.height = 150
self.init_ui()
def init_ui(self):
self.img.setPixmap(QtGui.QPixmap("someimage.png"))
h_final = QtWidgets.QHBoxLayout(self)
h_final.addWidget(self.img)
h_final.addWidget(self.btn_load)
self.btn_load.clicked.connect(self.loadafile)
self.setWindowTitle('This is main window')
self.setGeometry(600,150,self.width,self.height)
self.show()
#QtCore.pyqtSlot()
def loadafile(self):
filename, _ = QtWidgets.QFileDialog.getOpenFileName(self, 'Open File', os.getenv('HOME'))
with open(filename, 'r') as f:
file_text = f.read()
self.textChanged.emit(file_text)
def main():
app = QtWidgets.QApplication(sys.argv)
main = Window()
s = SecondWindow()
main.textChanged.connect(s.text.append)
sys.exit(app.exec_())
if __name__ == '__main__':
main()

Categories