0

I've got a MainWindow where I call a subwindow (pop-up) from a pushbutton and I'm unable to access def updateTime(self) and it gives me an attribute error:

AttributeError: 'MainWindow' object has no attribute 'updateTime'

If I take out the MainWindow section it works fine so I really don't understand what the problem is. Any help would be greatly appreciated.

from PyQt4 import QtGui, QtCore
from PyQt4 import *
from PyQt4.QtCore import *
import sys

CurrentTime = 0

class MainWindow(QtGui.QMainWindow):
    def __init__(self, parent=None):
        QtGui.QMainWindow.__init__(self, parent)
        self.central = QtGui.QWidget(self)
        self.setCentralWidget(self.central)

        self.hboxPB = QtGui.QHBoxLayout()
        self.vboxPB = QtGui.QVBoxLayout()
        self.MyButton = QtGui.QPushButton(self.central)
        self.MyButton.setText("Push Me")
        self.hboxPB.addWidget(self.MyButton)
        self.vboxPB.addLayout(self.hboxPB)
        self.MyButton.resize(90,90)
        self.MyButton.clicked.connect(lambda: widgetWindow.start(self))

class widgetWindow(QtGui.QWidget):
    def __init__(self, parent = None):
        QtGui.QWidget.__init__(self,parent)
        super(widgetWindow, self).__init__()
        widgetWindow.start(self)

    def start(self):
        window = QtGui.QMainWindow(self)
        window.setAttribute(QtCore.Qt.WA_DeleteOnClose)
        CentralWidget = QtGui.QWidget()
        self.timeSlider = QtGui.QSlider(QtCore.Qt.Horizontal, self)
        CentralWidgetLayout = QtGui.QHBoxLayout()
        VBox = QtGui.QVBoxLayout()
        CentralWidgetLayout.addWidget(self.timeSlider)
        VBox.addLayout(CentralWidgetLayout)
        CentralWidget.setLayout(VBox)
        window.setCentralWidget(CentralWidget)
        window.show()

        self.timer = QtCore.QTimer()
        self.timer.timeout.connect(self.updateTime)
        self.timer.start(1000)

    def updateTime(self):
        global CurrentTime
        CurrentTime = CurrentTime + 1
        self.timeSlider.setValue(CurrentTime)

def main():
    app = QtGui.QApplication(sys.argv)
    win = MainWindow()
    win.show()
    win.resize(800,450)
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()
user3723727
  • 142
  • 1
  • 4
  • 15

2 Answers2

2

Your issue starts with the line

self.MyButton.clicked.connect(lambda: widgetWindow.start(self))

Let's de-construct what this is doing.

  1. You have a button, self.MyButton which exists within an instance of the class MainWindow (you instantiate the class in the main() function)

  2. You are connecting to the clicked signal of the button.

  3. The function you connect to this signal is a lambda function which calls a function in the class widgetWindow. Note that this is distinct from calling a method of an instance of a class. You are not instantiating a class here (you are not creating an object). You are saying, use the method definition start in the class widgetWindow but make it act on the object self where self is an instance of the class MainWindow.

Hopefully you are now starting to see the problem with what you did. Rather than creating an instance of your widgetWindow class, you tried to use a method from widgetWindow as if it was a method of MainWindow. I would suggest reading more on object oriented programming in Python to get your head around this if you are having trouble still (especially if you are unclear as to the distinction between a class and an object)

The solution is thus to create an instance of widgetWindow (rather than directly accessing the methods of the class), and connect your button to a method of that instance. I've modified your code to do this, which is posted below. I've commented the sections I've changed. If you have questions about what I've done, let me know.

from PyQt4 import QtGui, QtCore
from PyQt4 import *
from PyQt4.QtCore import *
import sys

CurrentTime = 0

class MainWindow(QtGui.QMainWindow):
    def __init__(self, parent=None):
        QtGui.QMainWindow.__init__(self, parent)
        self.central = QtGui.QWidget(self)
        self.setCentralWidget(self.central)

        self.hboxPB = QtGui.QHBoxLayout()
        self.vboxPB = QtGui.QVBoxLayout()
        self.MyButton = QtGui.QPushButton(self.central)
        self.MyButton.setText("Push Me")
        self.hboxPB.addWidget(self.MyButton)
        self.vboxPB.addLayout(self.hboxPB)
        self.MyButton.resize(90,90)

        # instantiate the widgetWindow (pass this window as the parent)
        self.widgetwindow = widgetWindow(self)
        # connect the button to the start method of this instance we created above
        self.MyButton.clicked.connect(self.widgetwindow.start)

# no need to subclass QWidget here. This is just a wrapper class to hold your main window
class widgetWindow(object):
    def __init__(self, parent = None):
        # Store the parent for use later
        self.parent = parent

    def start(self):
        # change the window parent to be the parent we stored in the __init__ method
        window = QtGui.QMainWindow(self.parent)
        window.setAttribute(QtCore.Qt.WA_DeleteOnClose)
        # Add a signal to stop the timer when the window is destroyed
        window.destroyed.connect(self.stopTimer)
        CentralWidget = QtGui.QWidget()
        # Change the parent to be the window we just created
        self.timeSlider = QtGui.QSlider(QtCore.Qt.Horizontal, window)
        CentralWidgetLayout = QtGui.QHBoxLayout()
        VBox = QtGui.QVBoxLayout()
        CentralWidgetLayout.addWidget(self.timeSlider)
        VBox.addLayout(CentralWidgetLayout)
        CentralWidget.setLayout(VBox)
        window.setCentralWidget(CentralWidget)
        window.show()

        self.timer = QtCore.QTimer()
        self.timer.timeout.connect(self.updateTime)
        self.timer.start(1000)

    def updateTime(self):
        global CurrentTime
        CurrentTime = CurrentTime + 1
        self.timeSlider.setValue(CurrentTime)

    # Method to stop the timer once the window is destroyed
    def stopTimer(self):
        self.timer.stop()

def main():
    app = QtGui.QApplication(sys.argv)
    win = MainWindow()
    win.show()
    win.resize(800,450)
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()
three_pineapples
  • 11,579
  • 5
  • 38
  • 75
-2

Try this:

from PyQt4 import QtGui, QtCore
from PyQt4 import *
from PyQt4.QtCore import *
import sys

CurrentTime = 0
class widgetWindow(QtGui.QWidget):
    def __init__(self, parent = None):
        QtGui.QWidget.__init__(self,parent)
        super(widgetWindow, self).__init__()
        widgetWindow.start(self)

    def start(self):
        window = QtGui.QMainWindow(self)
        window.setAttribute(QtCore.Qt.WA_DeleteOnClose)
        CentralWidget = QtGui.QWidget()
        self.timeSlider = QtGui.QSlider(QtCore.Qt.Horizontal, self)
        CentralWidgetLayout = QtGui.QHBoxLayout()
        VBox = QtGui.QVBoxLayout()
        CentralWidgetLayout.addWidget(self.timeSlider)
        VBox.addLayout(CentralWidgetLayout)
        CentralWidget.setLayout(VBox)
        window.setCentralWidget(CentralWidget)
        window.show()

        self.timer = QtCore.QTimer()
        self.timer.timeout.connect(self.updateTime)
        self.timer.start(1000)

    def updateTime(self):
        global CurrentTime
        CurrentTime = CurrentTime + 1
        self.timeSlider.setValue(CurrentTime)



class MainWindow(QtGui.QMainWindow,widgetWindow):#here add subclass
    def __init__(self, parent=None):
        QtGui.QMainWindow.__init__(self, parent)
        self.central = QtGui.QWidget(self)
        self.setCentralWidget(self.central)

        self.hboxPB = QtGui.QHBoxLayout()
        self.vboxPB = QtGui.QVBoxLayout()
        self.MyButton = QtGui.QPushButton(self.central)
        self.MyButton.setText("Push Me")
        self.hboxPB.addWidget(self.MyButton)
        self.vboxPB.addLayout(self.hboxPB)
        self.MyButton.resize(90,90)
        self.MyButton.clicked.connect(lambda: widgetWindow.start(self))



def main():
    app = QtGui.QApplication(sys.argv)
    win = MainWindow()
    win.show()
    win.resize(800,450)
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()

You had the wrong namespace. You must make sure that you use the proper namespace or the interpreter does not know the proper place to look for the class.

GEOCHET
  • 21,119
  • 15
  • 74
  • 98
dsgdfg
  • 1,492
  • 11
  • 18