TypeError: 'QLabel' object is not callable - pyqt4

When I run the demo program as below, the mainwindow will call the childwindow, then the childwindow will call a widget. I want to get some attribute of this widget such as "messageLabel",but it will report an error that TypeError: 'QLabel' object is not callable. Then how to modify this error? Thank you,
import sys
from PyQt4 import QtCore, QtGui
class MainWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__()
self.setWindowTitle("MainWindow Window!")
self.setGeometry(400, 400, 100, 100)
self.centerWidget = QtGui.QWidget()
self.setCentralWidget(self.centerWidget)
self.pushButton = QtGui.QPushButton("&Button")
layout = QtGui.QVBoxLayout()
layout.addWidget(self.pushButton)
self.centerWidget.setLayout(layout)
class ChildWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
super(ChildWindow, self).__init__(parent)
#QtGui.QMainWindow.__init__(self, parent)
self.setWindowTitle("Child Window!")
self.centerWidget = Widget(parent)
self.setCentralWidget(self.centerWidget)
class Widget(QtGui.QWidget):
def __init__(self, parent=None):
super(Widget, self).__init__()
self.messageLabel = QtGui.QLabel()
self.messageLabel.setText("How to get this message label?")
layout = QtGui.QVBoxLayout()
layout.addWidget(self.messageLabel)
self.setLayout(layout)
app = QtGui.QApplication(sys.argv)
myapp = MainWindow()
def showChildWindow():
child_win = ChildWindow(myapp)
child_win.show()
childLabel = child_win.centerWidget.messageLabel().text().__str__().__str__() #how to call the messageLabel?
print childLabel
myapp.show()
QtCore.QObject.connect(myapp.pushButton,QtCore.SIGNAL("clicked()"),showChildWindow)
sys.exit(app.exec_())

Related

PyQt5 button "clicked.connect()" not working when importing from class

I am running a test for clicked.connect failing issue.
I want to wrap all the widgets in the CentralWidget to a class called React. When I call React in CentralWidget, widgets like Button, self.writeLine and self.valLabel will show up, but when I pressed the react Button, it's not functioning, which is to update self.valLabel according to self.writeLine.
A snap shot: Buttom not working
I suspect that
Button.clicked.connect(self.BottomPressedTest) # no function when pressed
is not doing what is supposed to do. But have no clue why this is happening.
The entire test code is shown below,
from PyQt5 import QtCore, QtWidgets, QtGui
import sys
class CentralWidget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(CentralWidget, self).__init__(parent)
self.mainLayout = QtWidgets.QGridLayout()
self.setLayout(self.mainLayout)
panel = React(1).groupbox
self.mainLayout.addWidget(panel, 0, 0)
class React(QtWidgets.QGroupBox):
def __init__(self, ch):
self.value = 0
self.groupbox = QtWidgets.QGroupBox()
self.vbox = QtWidgets.QVBoxLayout()
self.groupbox.setLayout(self.vbox)
Button = QtWidgets.QPushButton('React')
Button.clicked.connect(self.BottomPressedTest) # no function when pressed
self.writeLine = QtWidgets.QSpinBox()#QLineEdit()
self.writeLine.setFont(QtGui.QFont('Arial', 16))
self.valLabel = QtWidgets.QLabel()
self.valLabel.setFont(QtGui.QFont('Arial', 20))
self.valLabel.setText(f'React: {self.value}')
self.vbox.addWidget(Button)
self.vbox.addWidget(self.valLabel)
self.vbox.addWidget(self.writeLine)
def BottomPressedTest(self):
print('React bottom pressed.')
self.valLabel.setText(f'React: {self.writeLine.text()}')
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.setWindowTitle(QtCore.QCoreApplication.applicationName())
self.centralWidget = CentralWidget()
self.setCentralWidget(self.centralWidget)
class MainApplication(QtWidgets.QApplication):
def __init__(self, argv: list):
super(MainApplication, self).__init__(argv)
self.mainWindow = MainWindow()
self.mainWindow.resize(200,200)
self.mainWindow.raise_()
self.mainWindow.show()
def main():
application = MainApplication([])
sys.exit(application.exec_())
if __name__ == "__main__":
main()
Edit
I changed the first few line in React to
class React(QtWidgets.QGroupBox):
def __init__(self, ch):
super().__init__()
self.value = 0
self.setStyleSheet('QGroupBox { color: white; border: 3px solid grey; }') #
self.vbox = QtWidgets.QVBoxLayout()
self.setLayout(self.vbox)
, and then change CentralWidget to
class CentralWidget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(CentralWidget, self).__init__(parent)
self.mainLayout = QtWidgets.QGridLayout()
self.setLayout(self.mainLayout)
panel = React(1)
self.mainLayout.addWidget(panel)
Now the problem is solved. Many thanks to #musicamante and #Passerby
Your React object is thrown away at the end of CentralWidget.__init__, with only the QGroupBox persisting. Save it in an attribute and your problem will be solved.
Note that your React object inherits from QGroupBox, but does not call its __init__ method, instead creating a new QGroupBox as a member.

pyqt signal from a window not changing the main window widgets

I can pass values between two windows using signal,
and I want the plain text change, while I press a button from another window.
but the insertPlainText and even text.show() are not working
I've tried sending the signal to the init part of the Mainwindow,
tried update, repaint, but none of them works.
appreciate for any of your help, thanks!
the search_send method in class SearchWindow to MainWindow method test_
class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.ui = Ui_Dialog()
self.ui.setupUi(self)
self.ui.tag_box.hide()
def test_(self, i): # -------problem here------------------
print(i) // <- value here were right
self.ui.tag_box.insertPlainText(i) # -------Plain Text does not change-------
self.ui.tag_box.show()# -------Plain Text does not show either--------------
class SearchWindow(QtWidgets.QMainWindow):
signal=pyqtSignal(str)
def __init__(self, endpoint=None, user=None, password=None, points_link=None):
super(SearchWindow, self).__init__()
self.ui = Ui_Search()
self.ui.setupUi(self)
self.ui.pushButton_2.clicked.connect(self.search_send)
def search_send(self): # -------problem here------------------
tag_list = [tag1,tag2, tag3]
otherClass = MainWindow()
self.signal.connect(otherClass.test_)
for k in tag_list:
self.signal.emit(k)
if __name__ == '__main__':
app = QtWidgets.QApplication([])
window = MainWindow()
window.show()
sys.exit(app.exec_())
As we're unclear what Ui_Dialog contains, I can't tell what's wrong exactly, but can show you how Signal should be used.
This is example of Signal that's transferring text to Slot. Name may differ in PyQt5 - change accordingly.
from PySide2.QtWidgets import QWidget, QApplication, QPlainTextEdit, QTextEdit, QVBoxLayout
from PySide2.QtCore import Signal, Slot
import sys
class MainWindow(QWidget):
sig = Signal(str)
def __init__(self):
super(MainWindow, self).__init__()
self.setWindowTitle("Main")
self.layout = QVBoxLayout()
self.text = QTextEdit()
self.layout.addWidget(self.text)
self.setLayout(self.layout)
self.text.textChanged.connect(self.onChange)
def onChange(self):
self.sig.emit(self.text.toPlainText())
class SubWindow(QWidget):
def __init__(self, connect_target: MainWindow):
super(SubWindow, self).__init__()
self.setWindowTitle("Sub")
self.layout = QVBoxLayout()
self.text = QPlainTextEdit()
self.layout.addWidget(self.text)
self.setLayout(self.layout)
connect_target.sig.connect(self.onSignal)
#Slot(str)
def onSignal(self, text):
self.text.insertPlainText(text + '\r\n')
if __name__ == '__main__':
app = QApplication(sys.argv)
window = MainWindow()
window.show()
window_sub = SubWindow(window)
window_sub.show()
sys.exit(app.exec_())
Anything inside Main will be inserted to QPlainTextEdit as you wanted.

Cannot set header labels in tableview

So I want to change the labels of the tableview but keep getting an error when using the code I have found on other questions.
I am using the setHorizontalHeaderLabels code to add them.
class Setup(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(Setup, self).__init__(parent)
self.setWindowIcon(QtGui.QIcon('icon.png'))
self.initUI()
def initUI(self):
self.setWindowTitle('Auto-Annoucement - Setup')
self.showMaximized()
self.createTable()
self.setupmon = QWidget()
self.setup_layout = QVBoxLayout(self.setupmon)
self.setup_layout.addWidget(self.tableViewmon)
def createTable(self):
self.modelmon = QtGui.QStandardItemModel(self)
self.modelmon.setHorizontalHeaderLabels(self, ['Time', 'File Name'])
self.tableViewmon = QtWidgets.QTableView(self)
self.tableViewmon.setModel(self.modelmon)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
setup = Setup()
setup.show()
sys.exit(app.exec_())
I keep getting the error:
TypeError: setHorizontalHeader(self, QHeaderView): argument 1 has unexpected type 'Setup'
void QTableWidget::setHorizontalHeaderLabels(const QStringList &labels)
Sets the horizontal header labels using labels.
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
class Setup(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(Setup, self).__init__(parent)
self.setWindowIcon(QtGui.QIcon('icon.png'))
self.initUI()
def initUI(self):
self.setWindowTitle('Auto-Annoucement - Setup')
self.showMaximized()
self.createTable()
self.setupmon = QtWidgets.QWidget()
self.setCentralWidget(self.setupmon) # +++
self.setup_layout = QtWidgets.QVBoxLayout(self.setupmon)
self.setup_layout.addWidget(self.tableViewmon)
def createTable(self):
self.modelmon = QtGui.QStandardItemModel(self)
# self.modelmon.setHorizontalHeaderLabels(self, ['Time', 'File Name'])
self.modelmon.setHorizontalHeaderLabels(['Time', 'File Name']) # +++
self.tableViewmon = QtWidgets.QTableView(self)
self.tableViewmon.setModel(self.modelmon)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
setup = Setup()
setup.show()
sys.exit(app.exec_())

How to make "finish" button in QStackedWidget

I trying to create "Finish" button in QStackedWidget.
In a "checkButtons" function i checking current page index and set click events and text. I tried to check it by class name, but it doesn't work too.
Here is a code:
import sys
from PyQt5.QtGui import QIcon
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import (QApplication, QDialog, QComboBox, QStackedWidget, QWidget,
QPushButton, QLabel, QVBoxLayout, QHBoxLayout, QStyle)
class Main(QDialog):
def __init__(self, parent=None):
super(Main, self).__init__(parent)
# Main window setup
self.setWindowTitle("Stacked widget example")
self.setWindowIcon(self.style().standardIcon(QStyle.SP_FileDialogNewFolder))
self.setMinimumSize(400, 400)
self.setMaximumSize(640, 480)
self.rootVBox = QVBoxLayout()
self.rootHBox = QHBoxLayout()
self.rootHBox.addStretch()
self.rootVBox.addStretch()
self.pages = [FirstPage, SecondPage]
self.stacked = QStackedWidget(self)
for i in self.pages: self.stacked.addWidget(i(self))
self.pageState = True
self.buttonNext = QPushButton("Next")
self.buttonNext.clicked.connect(self.buttonNextConnect)
self.buttonBack = QPushButton("Back")
self.buttonBack.clicked.connect(self.buttonBackConnect)
self.rootHBox.addWidget(self.buttonBack)
self.rootHBox.addWidget(self.buttonNext)
self.rootVBox.addLayout(self.rootHBox)
self.setLayout(self.rootVBox)
def checkButtons(self):
print(self.stacked.currentIndex())
# I tried to check self.stacked.currentIndex() but it didn't work too
# if self.stacked.currentWidget().__class__ == self.pages[-1]:
if self.stacked.currentIndex() == len(self.pages) - 1:
self.buttonNext.setText("Finish")
self.buttonNext.clicked.connect(self.close)
elif self.stacked.currentIndex() < len(self.pages) - 1:
self.buttonNext.setText("Next")
self.buttonNext.clicked.connect(self.buttonNextConnect)
def buttonNextConnect(self):
self.stacked.setCurrentIndex(self.stacked.currentIndex() + 1)
self.checkButtons()
def buttonBackConnect(self):
self.stacked.setCurrentIndex(self.stacked.currentIndex() - 1)
self.checkButtons()
def finish(self):
self.close()
class FirstPage(QWidget):
def __init__(self, parent=None):
super(FirstPage, self).__init__(parent)
label = QLabel("First page")
rootVBox = QVBoxLayout()
rootHBox = QHBoxLayout()
rootHBox.addWidget(label)
rootVBox.addLayout(rootHBox)
self.setLayout(rootVBox)
class SecondPage(QWidget):
def __init__(self, parent=None):
super(SecondPage, self).__init__(parent)
label = QLabel("Second page")
rootVBox = QVBoxLayout()
rootHBox = QHBoxLayout()
rootHBox.addWidget(label)
rootVBox.addLayout(rootHBox)
self.setLayout(rootVBox)
if __name__ == '__main__':
app = QApplication(sys.argv)
main = Main()
main.show()
sys.exit(app.exec_())
If you try to press "next", "back" and then "next" again a program will be close. So, how can i fix it? Should i just make control buttons for each widget?
You must use the currentChanged signal of the QStackedWidget to know what page you are on and thus change the text, but in the buttonNextConnect slot you should check if you are already on the last page before switching to a new page, if you are then call to finish and if you do not change to another page
class Main(QDialog):
def __init__(self, parent=None):
super(Main, self).__init__(parent)
# Main window setup
self.setWindowTitle("Stacked widget example")
self.setWindowIcon(self.style().standardIcon(QStyle.SP_FileDialogNewFolder))
self.setMinimumSize(400, 400)
self.setMaximumSize(640, 480)
rootVBox = QVBoxLayout(self)
rootHBox = QHBoxLayout()
rootHBox.addStretch()
rootVBox.addStretch()
self.pages = [FirstPage, SecondPage]
self.stacked = QStackedWidget(self)
for i in self.pages: self.stacked.addWidget(i(self))
self.buttonNext = QPushButton("Next")
self.buttonNext.clicked.connect(self.buttonNextConnect)
self.buttonBack = QPushButton("Back")
self.buttonBack.clicked.connect(self.buttonBackConnect)
rootHBox.addWidget(self.buttonBack)
rootHBox.addWidget(self.buttonNext)
rootVBox.addLayout(rootHBox)
self.stacked.currentChanged.connect(self.on_currentChanged)
def buttonNextConnect(self):
if self.stacked.currentIndex() == self.stacked.count() -1:
self.finish()
if self.stacked.currentIndex() < self.stacked.count() -1:
self.stacked.setCurrentIndex(self.stacked.currentIndex() + 1)
def buttonBackConnect(self):
if self.stacked.currentIndex() > 0:
self.stacked.setCurrentIndex(self.stacked.currentIndex() - 1)
def on_currentChanged(self, index):
if index == self.stacked.count() -1:
self.buttonNext.setText("Finish")
else:
self.buttonNext.setText("Next")
def finish(self):
self.close()
Another option is to use QWizard and QWizardPage:
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
class Main(QtWidgets.QWizard):
def __init__(self, parent=None):
super(Main, self).__init__(parent)
buttons = [
QtWidgets.QWizard.Stretch,
QtWidgets.QWizard.BackButton,
QtWidgets.QWizard.NextButton,
QtWidgets.QWizard.FinishButton
]
self.setButtonLayout(buttons)
self.addPage(FirstPage())
self.addPage(SecondPage())
class FirstPage(QtWidgets.QWizardPage):
def __init__(self, parent=None):
super(FirstPage, self).__init__(parent)
self.setTitle("First page")
class SecondPage(QtWidgets.QWizardPage):
def __init__(self, parent=None):
super(SecondPage, self).__init__(parent)
self.setTitle("Second page")
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
main = Main()
main.show()
sys.exit(app.exec_())

How to avoid the child QMainWindow disappearing?

When I click the button, "ChildWindow" will flash and disappear. Then If I add the function exec_(), it will report an "AttributeError" because "QMainWindow" don't have this attribute.
How to modify the function "showChildWindow" so that it can work well? Thank you.
import sys
from PyQt4 import QtCore, QtGui
class MainWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.setWindowTitle("MainWindow Window!")
self.setGeometry(400, 400, 100, 100)
self.centerWidget = QtGui.QWidget()
self.setCentralWidget(self.centerWidget)
self.pushButton = QtGui.QPushButton("&Button")
layout = QtGui.QVBoxLayout()
layout.addWidget(self.pushButton)
self.centerWidget.setLayout(layout)
class ChildWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.setWindowTitle("Child Window!")
def showChildWindow():
mw = MainWindow()
child_win = ChildWindow(mw)
child_win.show()
#child_win.exec_() #AttributeError: 'ChildWindow' object has no attribute 'exec_'
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
myapp = MainWindow()
myapp.show()
QtCore.QObject.connect(myapp.pushButton,QtCore.SIGNAL("clicked()"),showChildWindow)
sys.exit(app.exec_())
This program can work well.
import sys
from PyQt4 import QtCore, QtGui
class MainWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.setWindowTitle("MainWindow Window!")
self.setGeometry(400, 400, 100, 100)
self.centerWidget = QtGui.QWidget()
self.setCentralWidget(self.centerWidget)
pushButton = QtGui.QPushButton("&Button")
layout = QtGui.QVBoxLayout()
layout.addWidget(pushButton)
self.centerWidget.setLayout(layout)
QtCore.QObject.connect(pushButton,QtCore.SIGNAL("clicked()"),self.showChildWindow)
def showChildWindow(self):
self.child_win = ChildWindow(self)
self.child_win.show()
class ChildWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.setWindowTitle("Child Window!")
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
myapp = MainWindow()
myapp.show()
sys.exit(app.exec_())
The real question appears to be: how do I access the main-window from other modules in my application?
My preferred general solution to this problem is to sub-class QApplication and add a simple accessor method, like this:
class Application(QtGui.QApplication):
def __init__(self):
QtGui.QApplication.__init__(self, sys.argv)
self._window = None
def window(self):
if self._window is None:
self._window = MainWindow()
return self._window
if __name__ == "__main__":
app = QtGui.qApp = Application()
app.window().show()
sys.exit(app.exec_())
With that in place, you can easily get access the methods of the main-window in other modules like this:
from PyQt4 import QtGui
QtGui.qApp.window().showChildWindow()
I had the same problem. The child QMainWindow would randomly disappear while interacting with the parent window.
This is the bad source code that causes this problem:
def showChildWindow(self):
child_win = ChildWindow()
child_win.show()
This is the good source code that fixes the problem:
def showChildWindow(self):
child_win = ChildWindow(self)
child_win.show()
When you instantiate the child window, make sure you pass the parent self.

Resources