Python Forum
Calling functions from within a class: PYQT6
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Calling functions from within a class: PYQT6
#1
Hi all,
My code is written in python and aims to output a GUI using PYQT6. The code below has been streamlined to troubleshoot the error:

1. From within the 'Widow' class, an instance of 'ButtonClass' class is called, which is named 'play_button'.

2. The 'ButtonClass' object, when clicked, sends a 'clicked.connect' signal to call the function 'button_visibility', which is contained within 'ButtonClass' class.

3. When the play_button is clicked, it produces the error below (described in 'The Returned Error:')


Does anybody know why I cannot access 'setVisible()' from within the 'button_visibility' function?


My code:

from PyQt6.QtWidgets import QApplication, QPushButton, QWidget
from PyQt6.QtGui import QIcon
from PyQt6.QtCore import *

import sys

class ButtonClass(QPushButton):
    mouseHover = pyqtSignal(bool)

    def __init__(self, parent, set_image,
                 set_button_geometry,
                 set_button_resize,
                 set_button_visible,
                 path_to_clicked_function,
                 button_name):

        super().__init__(parent)
        # Instance variables assigned with arguments
        self.set_image = set_image
        self.set_button_geometry = set_button_geometry
        self.set_button_resize = set_button_resize
        self.set_button_visible = set_button_visible
        self.path_to_clicked_function = path_to_clicked_function
        self.button_name = button_name

        self.setMouseTracking(True)

        # Assign icon to QPushButton object and insert custom image
        self.setIcon(QIcon(self.set_image))

        # Specify button geometry
        self.setGeometry(self.set_button_geometry[0],
                         self.set_button_geometry[1],
                         self.set_button_geometry[2],
                         self.set_button_geometry[3])

        # Specify Icon size
        self.setIconSize(QSize(self.set_button_resize[0],
                               self.set_button_resize[1]))

        # Stylesheet attributes
        self.setStyleSheet("border: 0px")

        # Set button visibility
        self.setVisible(self.set_button_visible)

        self.clicked.connect(ButtonClass.button_visibility)

    def button_visibility(self):
        self.setVisible(False)

    def enterEvent(self, event):
        self.mouseHover.emit(True)
        print("Button entered")

    def leaveEvent(self, event):
        self.mouseHover.emit(False)
        print("Button left")


class Window(QWidget):
    def __init__(self):
        super().__init__()
        # Define window title
        self.setWindowTitle("Soular")

        # Define window height
        self.setFixedHeight(700)

        # Define window width
        self.setFixedWidth(400)

        # window stylesheet defines window background colour
        self.setStyleSheet("background-color:'#323232'")

        # Moves main window to screen location
        self.move(10, 10)

        # initialises play_button from class 'Button_class'
        play_button = ButtonClass(self,
                    'Images/Play_standard.png',
                    [165, 580, 70, 70],
                    [70, 70],
                    True,
                    ButtonClass.button_visibility,
                    'play_button')

app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec())
The Returned Error:

Quote:Traceback (most recent call last):
File "/Users/Library/Mobile Documents/com~apple~CloudDocs/Python Projects/pythonProject5/UI.py", line 50, in button_visibility
self.setVisible(False)
AttributeError: 'bool' object has no attribute 'setVisible'

Process finished with exit code 134 (interrupted by signal 6: SIGABRT)
Reply
#2
In line 50 try changing self to play_button. Somehow self is a boolean at that point (according to the error) rather than the button.
Anon_Brown likes this post
Reply
#3
This code treats "button_visibility()" like a class method when it is really an instance method.
self.clicked.connect(ButtonClass.button_visibility)
The code should be written like this:
self.clicked.connect(self.button_visibility)
The reason you got an error message about 'bool' object has no attribute 'setVisible' was because you were not passing an instance (self) when calling the method.
Anon_Brown likes this post
Reply
#4
Thank you both for your help. The 'self.clicked.connect(self.button_visibility)' approach worked.
Reply
#5
I think it is a bad idea using setGeometry() to size and position your button in the window. I also think it is a bad idea passing the size and position as a parameter when you create the button. The ​common practice to use a geometry manager to place widgets in a window.

I don't think the button should have a button_visibility() method and I don't think the button should bind the clicked signal to call this method. What good is a button that hides itself? Buttons should not do things like set their size or bind their clicked events. Buttons should be generic reusable things. The application should use the button API to bind the events.

This is how I would write your code. I use PySide instead of PyQt, so there are some minor differences related to that. I also removed the style sheets and anything that is not absolutely required to demonstrate the issue related to the post topic. And just for fun I changed the hover event to not only emit a signal but change the button icon.
import sys
import PySide6.QtWidgets as QtWidgets
import PySide6.QtCore as QtCore
import PySide6.QtGui as QtGui

class HoverButton(QtWidgets.QPushButton):
    """A Pushbutton that changes it's icon when you hover"""
    hover = QtCore.Signal(bool)
 
    def __init__(self, parent, icon, hover_icon):
        super().__init__(parent)
        self.icon = icon
        self.hover_icon = hover_icon
        self.setMouseTracking(True)
        self.setIcon(self.icon)
 
    def enterEvent(self, event):
        self.setIcon(self.hover_icon)
        self.hover.emit(True)
 
    def leaveEvent(self, event):
        self.setIcon(self.icon)
        self.hover.emit(False)
 
class Window(QtWidgets.QWidget):
    """A window that demonstrates how to use my hover button"""
    def __init__(self):
        super().__init__()
        play_button = HoverButton(
                self,
                QtGui.QIcon("ttt_x.png"),
                QtGui.QIcon("ttt_o.png")
        )
        # Bind events outside the button
        play_button.hover.connect(lambda flag: print("Hover", flag))
        play_button.clicked.connect(lambda flag: play_button.setVisible(False))

        layout = QtWidgets.QVBoxLayout(self)
        layout.addWidget(play_button)
 
app = QtWidgets.QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec())
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Calling functions by making part of their name with variable crouzilles 4 812 Nov-02-2023, 12:25 PM
Last Post: noisefloor
  PyRun_SimpleFile calling multiprocessing Python Class cause endless init loop Xeno 2 1,036 Sep-19-2022, 02:32 AM
Last Post: Xeno
  Calling a base class variable from an inherited class CompleteNewb 3 1,673 Jan-20-2022, 04:50 AM
Last Post: CompleteNewb
  Calling a class from a function jc4d 5 1,808 Dec-17-2021, 09:04 PM
Last Post: ndc85430
  Why built in functions are defined as class? quazirfan 5 2,771 Oct-23-2021, 01:20 PM
Last Post: Gribouillis
  should I ... go class or stick with functions? 3Pinter 4 2,070 Nov-14-2020, 10:40 AM
Last Post: 3Pinter
Question trouble with functions "def", calling/defining them Duck_Boom 13 4,354 Oct-21-2020, 03:50 AM
Last Post: Duck_Boom
  NameError when calling a class method mfreudenberg 2 2,297 Sep-25-2020, 07:40 AM
Last Post: mfreudenberg
  calling on a method from one class into another class which is not a child NABA 5 2,807 Apr-29-2020, 07:49 PM
Last Post: deanhystad
  using class functions in roguelike game trousers1 3 2,557 Dec-02-2019, 08:22 PM
Last Post: ichabod801

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020