Issue
I am a pyside6 learner. And I am trying to create a clock based on pyside6, and I'd like to change its font color on click. How can I make it work?
The following codes are parts of this project.
class Clock(QWidget):
def __init__(self, parent=None) -> None:
super().__init__(parent)
self.left = 1100
self.top = 800
self.width = 320
self.height = 60
# Menu
self.setContextMenuPolicy(Qt.CustomContextMenu)
self.customContextMenuRequested.connect(self.mouseRightMenu)
# Font
self.font_color = 'blue'
# UI
self.initUI()
def changeFontColor(self, fcolor) -> None:
self.font_color = fcolor
def mouseRightMenu(self, pos) -> None:
self.menu = QMenu(self)
# font color
fontColorMenu = self.menu.addMenu('font color')
self.actionB1 = QAction('black', self)
self.actionB2 = QAction('red', self)
self.actionB3 = QAction('yellow', self)
self.actionB1.triggered.connect(self.changeFontColor('black'))
def initUI(self) -> None:
# geometry of main window
self.setGeometry(self.left, self.top, self.width, self.height)
# label object
self.label = QLabel()
self.label.setAlignment(Qt.AlignCenter)
self.label.setFont(font)
self.label.setStyleSheet(f'color:{self.font_color};')
if __name__ == '__main__':
App = QApplication(sys.argv)
clock = Clock()
clock.show() # show all the widgets
App.exit(App.exec()) # start the app
Currently changeFontColor
function doesn't work, I don't know what I have miss here.
Solution
You are missing two fundamental aspects.
First of all self.font_color
is just a variable (or, to be precise, an attribute).
You are explicitly using it within initUi()
along with self.label.setStyleSheet()
, but that doesn't "magically" make that variable interactive.
What you're doing would never work, and here's a basic explanation:
color = 'blue'
styleSheet = f'color: {color}'
print(styleSheet)
color = 'green'
print(styleSheet)
If you consider the above, both the print statements will return the same value: changing color
doesn't change styleSheet
.
That is mostly due to the fact that strings are immutable types (so, styleSheet
can never be affected by any change in color
), but also because there's no dynamic relation between color
and styleSheet
.
What actually changes the aspect of a widget is an explicit call to setStyleSheet()
, and changing the string contents used for a previous call is completely useless. You must call setStyleSheet()
again in order to apply it.
Then, you're doing another mistake: signal connections use callables, but you're explicitly calling the changeFontColor()
function.
Consider this:
def myFunction(arg):
print(f'arg is "{arg}"')
return arg
# this is a call (note the parentheses), which will *execute* the function
>>> myFunction('hello')
# and will show the follwing:
arg is "hello"
# while the following will show a different result:
>>> print(myFunction('hello'))
arg is "hello"
hello
# this is a reference, which will do nothing
>>> myFunction
<function __main__.myFunction>
# notice tht difference with the above:
>>> print(myFunction)
<function myFunction at 0xZZZZZZZZ>
Using self.someObject.someSignal.connect(someFunction())
is wrong, (unless someFunction
returns a reference to another function).
You're directly calling your function (that doesn't return a callable), which actually prompts an error. You probably didn't notice (IDEs are often unable to show all output and full tracebacks, and most Qt errors are not fatal), but if you run your program in a terminal or prompt you'll probably see an error saying that a TypeError
occurred, because you're trying to connect to a NoneType
.
What you need to do is the following:
def changeFontColor(self, fcolor) -> None:
# explicitly call setStyleSheet() with the color name
self.label.setStyleSheet(f'color: {fcolor};')
def mouseRightMenu(self, pos) -> None:
# ...
self.actionB1.triggered.connect(lambda:
self.changeFontColor('black'))
lambda
creates a function reference, but doesn't call it: when the triggered
signal is emitted, the function will finally be called.
The above is similar to the following:
def changeFontColor(self) -> None:
self.label.setStyleSheet('color: black')
def mouseRightMenu(self, pos) -> None:
# ...
self.actionB1.triggered.connect(self.changeFontColor)
With the difference that we directly call the function, which internally uses a static value ('black'
).
I strongly suggest you to do some research on object references, callables, and object types.
Answered By - musicamante
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.