In this article we will see how to change the size of push button. There are basically two ways in order to change the size of button i.e using resize
method and setGeometry
method.
The main difference between them is resize
method will only resize the push button. on the other hand setGeometry
method will change the size and also set the position of the push button.
Способ №1:
Syntax : button.setGeometry(left, top, width, height)
Argument : It takes four integer as argument, first two are the position and second two are the size.
Action performed : It sets the position and the size of push button.
Code :
from
PyQt5.QtWidgets
import
*
from
PyQt5.QtGui
import
*
from
PyQt5.QtCore
import
*
import
sys
class
Window(QMainWindow):
def
__init__(
self
):
super
().__init__()
self
.setWindowTitle(
"Python "
)
self
.setGeometry(
100
,
100
,
600
,
400
)
self
.UiComponents()
self
.show()
def
UiComponents(
self
):
button
=
QPushButton(
"CLICK"
,
self
)
button.setGeometry(
200
,
150
,
100
,
40
)
button.clicked.connect(
self
.clickme)
def
clickme(
self
):
print
(
"pressed"
)
App
=
QApplication(sys.argv)
window
=
Window()
sys.exit(App.
exec
())
Выход :
Способ №2:
Syntax : button.resize(width, height)
Argument : It takes two integer as argument i.e width and height.
Action performed : It sets the size of push button
Code :
from
PyQt5.QtWidgets
import
*
from
PyQt5.QtGui
import
*
from
PyQt5.QtCore
import
*
import
sys
class
Window(QMainWindow):
def
__init__(
self
):
super
().__init__()
self
.setWindowTitle(
"Python "
)
self
.setGeometry(
100
,
100
,
600
,
400
)
self
.UiComponents()
self
.show()
def
UiComponents(
self
):
button
=
QPushButton(
"CLICK"
,
self
)
button.resize(
150
,
50
)
button.clicked.connect(
self
.clickme)
def
clickme(
self
):
print
(
"pressed"
)
App
=
QApplication(sys.argv)
window
=
Window()
sys.exit(App.
exec
())
Выход :
Внимание компьютерщик! Укрепите свои основы с помощью базового курса программирования Python и изучите основы.
Для начала подготовьтесь к собеседованию. Расширьте свои концепции структур данных с помощью курса Python DS. А чтобы начать свое путешествие по машинному обучению, присоединяйтесь к курсу Машинное обучение — базовый уровень.
The push button, or command button, is perhaps the most commonly used widget in any graphical user interface (GUI). A button is a rectangular widget that typically displays a text describing its aim.
When we click a button, we command the computer to perform actions or to answer a question. Typical buttons include Ok, Apply, Cancel, Close, Yes, No and Help. However, they’re not restricted to this list.
In this tutorial, you’ll learn how to create and customize button widgets in your GUI applications.
Buttons are probably the most common widgets in GUI applications. They come in handy when you need to create dialogs for communicating with your users. You’ll probably be familiar with Accept, Ok, Canel, Yes, No, and Apply buttons, which are commonplace in modern graphical user interfaces.
In general, buttons allow you to trigger actions in response to the user’s clicks on the button’s area. Buttons often have a rectangular shape and include a text label that describes their intended action or command.
If you’ve used PyQt or PySide to create GUI applications in Python, then it’d be pretty likely that you already know about the QPushButton
class. This class allows you to create buttons in your graphical interfaces quickly.
The QPushButton
class provides three different constructors that you can use to create buttons according to your needs:
Constructor | Description |
---|---|
QPushButton(parent: QWidget = None) |
Constructs a button with a parent widget but without text or icon |
QPushButton(text: str, parent: QWidget = None) |
Constructs a button with a parent widget and the description text but without an icon |
QPushButton(icon: QIcon, text: str, parent: QWidget = None) |
Constructs a button with an icon, text, and parent widget |
To illustrate how to use the above constructors, you can code the following example:
- PyQt6
- PySide6
python
import sys
from PyQt6.QtCore import QSize
from PyQt6.QtGui import QIcon
from PyQt6.QtWidgets import QApplication, QPushButton, QVBoxLayout, QWidget
class Window(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
# Button with a parent widget
topBtn = QPushButton(parent=self)
topBtn.setFixedSize(100, 60)
# Button with a text and parent widget
centerBtn = QPushButton(text="Center", parent=self)
centerBtn.setFixedSize(100, 60)
# Button with an icon, a text, and a parent widget
bottomBtn = QPushButton(
icon=QIcon("./icons/logo.svg"),
text="Bottom",
parent=self
)
bottomBtn.setFixedSize(100, 60)
bottomBtn.setIconSize(QSize(40, 40))
layout = QVBoxLayout()
layout.addWidget(topBtn)
layout.addWidget(centerBtn)
layout.addWidget(bottomBtn)
self.setLayout(layout)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec())
python
import sys
from PySide6.QtCore import QSize
from PySide6.QtGui import QIcon
from PySide6.QtWidgets import QApplication, QPushButton, QVBoxLayout, QWidget
class Window(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
# Button with a parent widget
topBtn = QPushButton(parent=self)
topBtn.setFixedSize(100, 60)
# Button with a text and parent widget
centerBtn = QPushButton(text="Center", parent=self)
centerBtn.setFixedSize(100, 60)
# Button with an icon, a text, and a parent widget
bottomBtn = QPushButton(
icon=QIcon("./icons/logo.svg"),
text="Bottom",
parent=self
)
bottomBtn.setFixedSize(100, 60)
bottomBtn.setIconSize(QSize(40, 40))
layout = QVBoxLayout()
layout.addWidget(topBtn)
layout.addWidget(centerBtn)
layout.addWidget(bottomBtn)
self.setLayout(layout)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec())
You can download the logo here or use your own image file. You can also use PNG format images if you prefer.
This code does a lot! First, we do the required imports. Inside our Window
class, we create three QPushButton
instances. To create the first button, we use the first constructor of QPushButton
. That’s why we only pass a parent
widget.
For the second button, we use the second constructor of QPushButton
. This time, we provide the button’s text and parent. Note that the text is a regular Python string.
Our last button uses the third constructor. In this case, we need to provide the button’s icon, text, and parent. We use the QIcon
class with an SVG image as an argument to provide the icon. Note that we can also use a QPixmap
object as the button’s icon.
Save this code to a .py
file and run it. You’ll get a window that looks something like this:
QPushButton constructors example, showing three buttons with labels & icon
The first button has no text. It’s just a rectangular shape on the app’s windows. The second button in the center has text only, while the third button at the bottom of the window has an icon and text. That looks great!
These buttons don’t do any action jet. If you click them, then you’ll realize that nothing happens. To make your buttons perform concrete actions, you need to connect their signals to some useful slots. You’ll learn how to do this in the next section.
Connecting Signals and Slots
Depending on specific user events, the QPushButton
class can emit four different signals. Here’s is a summary of these signals and their corresponding meaning:
Signal | Emitted |
---|---|
clicked(checked=false) |
When the user clicks the button and activates it. |
pressed() |
When the user presses the button down. |
released() |
When the user releases the button. |
toggled(checked=false) |
Whenever a checkable button changes its state from checked to unchecked and vice versa. |
When you’re creating a GUI application, and you need to use buttons, then you need to think of the appropriate signal to use. Most of the time, you’ll use the button’s clicked()
signal since clicking a button is the most common user event you’ll ever need to process.
The other part of the signal and slot equation is the slot itself. A slot is a method or function that performs a concrete action in your application. Now, how can you connect a signal to a slot so that the slot gets called when the signal gets emitted? Here’s the required syntax to do this:
python
button.<signal>.connect(<method>)
In this construct, button
is the QPushButton
object we need to connect with a given slot. The <signal>
placeholder can be any of the four abovementioned signals. Finally, <method>
represents the target slot or method.
Let’s write an example that puts this syntax into action. For this example, we’ll connect the clicked
signal with a method that counts the clicks on a button:
- PyQt6
- PySide6
python
import sys
from PyQt6.QtWidgets import QApplication, QPushButton, QVBoxLayout, QWidget
class Window(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.count = 0
self.button = QPushButton(f"Click Count: {self.count}", self)
self.button.setFixedSize(120, 60)
self.button.clicked.connect(self.count_clicks)
layout = QVBoxLayout()
layout.addWidget(self.button)
self.setLayout(layout)
def count_clicks(self):
self.count += 1
self.button.setText(f"Click Count: {self.count}")
if __name__ == "__main__":
app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec())
python
import sys
from PySide6.QtWidgets import QApplication, QPushButton, QVBoxLayout, QWidget
class Window(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.count = 0
self.button = QPushButton(f"Click Count: {self.count}", self)
self.button.setFixedSize(120, 60)
self.button.clicked.connect(self.count_clicks)
layout = QVBoxLayout()
layout.addWidget(self.button)
self.setLayout(layout)
def count_clicks(self):
self.count += 1
self.button.setText(f"Click Count: {self.count}")
if __name__ == "__main__":
app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec())
The button
variable holds an instance of QPushButton
. To create this button, we use a text and parent widget. This parent widget works as our current window. Then we connect the button’s clicked
signal with the count_clicks()
method.
The count_clicks()
method counts the number of clicks on the button and updates the button’s text accordingly. Go ahead and run the app!
Exploring the Public API of QPushButton
Up to this point, you’ve learned about the different ways to create buttons in your GUI applications. You’ve also learned how to make your buttons perform actions in response to the user’s actions by connecting the buttons’ signals with concrete methods known as slots.
In the following sections, you’ll learn about the QPushButton
class’s public API and its most useful properties, including the following:
Property | Description | Getter Method | Setter Method |
---|---|---|---|
text |
Holds the text shown on the button | text() |
setText() |
icon |
Holds the icon shown on the button | icon() |
setIcon() |
shortcut |
Holds the keyboard shortcut associated with the button | shortcut() |
setShortcut() |
Let’s kick things off by learning how to set and get a button’s text, icon, and keyboard shortcut. These actions can be an essential part of your GUI design process.
Setting a Button’s Text, Icon, and Shortcut
In previous sections, you’ve learned how to create buttons using different class constructors. Some of these constructors allow you to set the button’s text directly. However, sometimes you need to manipulate a button’s text at runtime. To accomplish this, you can use setText()
and text()
.
As its name suggests, the setText()
method allows you to set the text of a given button. On the other hand, the text()
lets you retrieve the current text of a button. Here’s a toy example of how to use these methods:
- PyQt6
- PySide6
python
import sys
from PyQt6.QtWidgets import QApplication, QPushButton, QVBoxLayout, QWidget
class Window(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.button = QPushButton("Hello!")
self.button.setFixedSize(120, 60)
self.button.clicked.connect(self.onClick)
layout = QVBoxLayout()
layout.addWidget(self.button)
self.setLayout(layout)
def onClick(self):
text = self.button.text()
if text == "Hello!":
self.button.setText(text[:-1] + ", World!")
else:
self.button.setText("Hello!")
if __name__ == "__main__":
app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec())
python
import sys
from PySide6.QtWidgets import QApplication, QPushButton, QVBoxLayout, QWidget
class Window(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.button = QPushButton("Hello!")
self.button.setFixedSize(120, 60)
self.button.clicked.connect(self.onClick)
layout = QVBoxLayout()
layout.addWidget(self.button)
self.setLayout(layout)
def onClick(self):
text = self.button.text()
if text == "Hello!":
self.button.setText(text[:-1] + ", World!")
else:
self.button.setText("Hello!")
if __name__ == "__main__":
app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec())
In this example, we use text()
and setText()
inside the onClick()
method to manipulate the text of our button object. These methods come in handy when we need to set and retrieve a button’s text at run time, which would be useful in a few situations. For example, if we need a button to fold and unfold a tree of widgets or other objects.
Go ahead and run the app! You’ll get a window like the following:
Window with a single button, with the text Hello! Click to change the text.
In this example, when you click the button, its text alternate between Hello!
and Hello, World!
.
QPushButton
also has methods to manipulate the icon of a given button. In this case, the methods are setIcon()
and icon()
. You can set the button’s icon at run time with the first method. The second method allows you to retrieve the icon of a given button. There’s also a third method related to icons. It’s called .setIconSize()
and allows you to manipulate the icon size.
Here’s an example that illustrates how to use these methods:
- PyQt6
- PySide6
python
import sys
from PyQt6.QtCore import QSize
from PyQt6.QtGui import QIcon
from PyQt6.QtWidgets import QApplication, QPushButton, QVBoxLayout, QWidget
class Window(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.btnOne = QPushButton(
icon=QIcon("./icons/logo.svg"), text="Click me!", parent=self
)
self.btnOne.setFixedSize(100, 60)
self.btnOne.clicked.connect(self.onClick)
self.btnTwo = QPushButton(parent=self)
self.btnTwo.setFixedSize(100, 60)
self.btnTwo.setEnabled(False)
self.btnTwo.clicked.connect(self.onClick)
layout = QVBoxLayout()
layout.addWidget(self.btnOne)
layout.addWidget(self.btnTwo)
self.setLayout(layout)
def onClick(self):
sender = self.sender()
icon = sender.icon()
if sender is self.btnOne:
sender.setText("")
sender.setIcon(QIcon())
sender.setEnabled(False)
self.btnTwo.setEnabled(True)
self.btnTwo.setText("Click me!")
self.btnTwo.setIcon(icon)
self.btnTwo.setIconSize(QSize(20, 20))
elif sender is self.btnTwo:
sender.setText("")
sender.setIcon(QIcon())
sender.setEnabled(False)
self.btnOne.setEnabled(True)
self.btnOne.setText("Click me!")
self.btnOne.setIcon(icon)
self.btnOne.setIconSize(QSize(30, 30))
if __name__ == "__main__":
app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec())
python
import sys
from PySide6.QtCore import QSize
from PySide6.QtGui import QIcon
from PySide6.QtWidgets import QApplication, QPushButton, QVBoxLayout, QWidget
class Window(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.btnOne = QPushButton(
icon=QIcon("./icons/logo.svg"), text="Click me!", parent=self
)
self.btnOne.setFixedSize(100, 60)
self.btnOne.clicked.connect(self.onClick)
self.btnTwo = QPushButton(parent=self)
self.btnTwo.setFixedSize(100, 60)
self.btnTwo.setEnabled(False)
self.btnTwo.clicked.connect(self.onClick)
layout = QVBoxLayout()
layout.addWidget(self.btnOne)
layout.addWidget(self.btnTwo)
self.setLayout(layout)
def onClick(self):
sender = self.sender()
icon = sender.icon()
if sender is self.btnOne:
sender.setText("")
sender.setIcon(QIcon())
sender.setEnabled(False)
self.btnTwo.setEnabled(True)
self.btnTwo.setText("Click me!")
self.btnTwo.setIcon(icon)
self.btnTwo.setIconSize(QSize(20, 20))
elif sender is self.btnTwo:
sender.setText("")
sender.setIcon(QIcon())
sender.setEnabled(False)
self.btnOne.setEnabled(True)
self.btnOne.setText("Click me!")
self.btnOne.setIcon(icon)
self.btnOne.setIconSize(QSize(30, 30))
if __name__ == "__main__":
app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec())
In this example, we create an app with two buttons. Both buttons are connected to the onClick()
method. Inside the method, we first get the clicked button using the sender()
method on our app’s window, self
.
Next, we get a reference to the sender button’s icon using the icon()
method. The if
statement checks if the clicked object was btnOne
. If that’s the case, then we reset the icon with setIcon()
and disable the button with setEnabled()
. The following four lines enable the btnTwo
button, set its text to "Click me!"
, change the button’s icon, and resize the icon. The elif
clause does something similar, but this time the target button is btnOne
.
If you run this application, then you’ll get a window like this:
Window with two buttons, the top with a icon & label, the bottom empty. Click to toggle which button has the label & icon.
When we click the top button, the bottom button’s text and icon will be set to Click me!
and to the PythonGUIs.com logo, respectively. At the same time, the top button’s text and icon will disappear. Note that the logo’s size will change as well.
Another useful feature of buttons is that you can assign them a keyboard shortcut for those users that prefer the keyboard over the mouse. These methods are .setShortcut()
and .shortcut()
. Again, you can use the first method to set a shortcut and the second method to get the shortcut assigned to the underlying button.
These methods are commonly helpful in situations where we have a button that doesn’t have any text. Therefore we can’t assign it an automatic shortcut using the ampersand character &
.
Checking the Status of a Button
Sometimes you’d need to check the status of a given button and take action accordingly. The QPushButton
class provides a few methods that can help you check different properties related to the current status of your buttons:
Property | Description | Access Method | Setter Method |
---|---|---|---|
down |
Indicates whether the button is pressed down or not | isDown() |
setDown() |
checked |
Indicates whether the button is checked or not | isChecked() |
setChecked() |
enabled |
Indicates whether the button is enabled or not | isEnabled() |
setEnabled() |
The down status is typically transitory and naturally happens between the pressed and released statuses. However, we can use the setDown()
method to manipulate the down status at runtime.
The checked status is only available when we use checkable buttons. Only checkable buttons can be at either the checked or unchecked status.
Finally, when we enable or disable a given button, we allow or disallow the user’s click on the button. In other words, disabled buttons don’t respond to the user’s clicks or other events, while enabled buttons do respond.
Here’s an example that shows how these three sets of statuses work:
- PyQt6
- PySide6
python
import sys
from PyQt6.QtWidgets import QApplication, QPushButton, QVBoxLayout, QWidget
class Window(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.btnOne = QPushButton(text="I'm Down!", parent=self)
self.btnOne.setFixedSize(150, 60)
self.btnOne.setDown(True)
self.btnOne.clicked.connect(self.onBtnOneClicked)
self.btnTwo = QPushButton(text="I'm Disabled!", parent=self)
self.btnTwo.setFixedSize(150, 60)
self.btnTwo.setEnabled(False)
self.btnThree = QPushButton(text="I'm Checked!", parent=self)
self.btnThree.setFixedSize(150, 60)
self.btnThree.setCheckable(True)
self.btnThree.setChecked(True)
self.btnThree.clicked.connect(self.onBtnThreeClicked)
layout = QVBoxLayout()
layout.addWidget(self.btnOne)
layout.addWidget(self.btnTwo)
layout.addWidget(self.btnThree)
self.setLayout(layout)
def onBtnOneClicked(self):
if not self.btnOne.isDown():
self.btnOne.setText("I'm Up!")
self.btnOne.setDown(False)
def onBtnThreeClicked(self):
if self.btnThree.isChecked():
self.btnThree.setText("I'm Checked!")
else:
self.btnThree.setText("I'm Unchecked!")
if __name__ == "__main__":
app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec())
python
import sys
from PySide6.QtWidgets import QApplication, QPushButton, QVBoxLayout, QWidget
class Window(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.btnOne = QPushButton(text="I'm Down!", parent=self)
self.btnOne.setFixedSize(150, 60)
self.btnOne.setDown(True)
self.btnOne.clicked.connect(self.onBtnOneClicked)
self.btnTwo = QPushButton(text="I'm Disabled!", parent=self)
self.btnTwo.setFixedSize(150, 60)
self.btnTwo.setEnabled(False)
self.btnThree = QPushButton(text="I'm Checked!", parent=self)
self.btnThree.setFixedSize(150, 60)
self.btnThree.setCheckable(True)
self.btnThree.setChecked(True)
self.btnThree.clicked.connect(self.onBtnThreeClicked)
layout = QVBoxLayout()
layout.addWidget(self.btnOne)
layout.addWidget(self.btnTwo)
layout.addWidget(self.btnThree)
self.setLayout(layout)
def onBtnOneClicked(self):
if not self.btnOne.isDown():
self.btnOne.setText("I'm Up!")
self.btnOne.setDown(False)
def onBtnThreeClicked(self):
if self.btnThree.isChecked():
self.btnThree.setText("I'm Checked!")
else:
self.btnThree.setText("I'm Unchecked!")
if __name__ == "__main__":
app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec())
In this example, we first set btnOne
down using the setDown()
method. Then we disable btnTwo
using the setEnabled()
with False
as an argument. This will make this button unresponsive to user events. Finally, we set btnThree
as checkable with setCheckable()
. Being checkable means that we can use the checked and unchecked statuses in our code.
The onBtnOneClicked()
method is connected to btnOne
. This method checks if the button is not down and changes the button text accordingly.
The onBtnThreeClicked()
is connected to btnThree
. This method alternatively changes the button’s text depending on its checked status.
If you run this app, you’ll get the following window:
Window with 3 buttons: one starting in the down state, one disabled and one checked & toggleable.
First, note that these three buttons have different tones of gray. These different tones of gray indicate three different states. The first button is down, the second button is disabled, and the third button is checked.
If you click the first button, then it’ll be released, and its text will be set to I'm Up!
. The second button won’t respond to your clicks or actions. The third button will alternate its status between unchecked and checked.
Exploring Other Properties of Button Objects
QPushButton
has several other useful properties we can use in our GUI applications. Some of these properties with their corresponding setter and getter method include:
Property | Description | Access Method | Setter Method |
---|---|---|---|
default |
Indicates whether the button is the default button on the containing window or not | isDefault() |
setDefault() |
flat |
Indicates whether the button border is raised or not | isFlat() |
setFlat() |
The default
property comes in handy when you have several buttons on a window, and you need to set one of these buttons as the default window’s action. For example, say we have a dialog with the Ok and Cancel buttons. In this case, the Ok button can be your default action.
The flat
property is closely related to the look and feel of your app’s GUI. If we set flat
to True
, then the button’s border won’t be visible.
Over 10,000 developers have bought Create GUI Applications with Python & Qt!
[[ discount.discount_pc ]]% OFF for
the next [[ discount.duration ]]
[[discount.description ]]
with the code [[ discount.coupon_code ]]
Purchasing Power Parity
Developers in [[ country ]] get [[ discount.discount_pc ]]% OFF on all books & courses
with code [[ discount.coupon_code ]]
QPushButton
objects can also display a menu when you click them. To set up this menu, you must have a proper popup menu beforehand. Then you can use the setMenu()
method to associate the menu with the button.
Here’s an example that creates a button with an attached popup menu:
- PyQt6
- PySide6
python
import sys
from PyQt6.QtWidgets import (
QApplication,
QMenu,
QPushButton,
QVBoxLayout,
QWidget,
)
class Window(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.btnOne = QPushButton(text="Menu!", parent=self)
self.menu = QMenu(self)
self.menu.addAction("First Item")
self.menu.addAction("Second Item")
self.menu.addAction("Third Item")
self.btnOne.setMenu(self.menu)
layout = QVBoxLayout()
layout.addWidget(self.btnOne)
self.setLayout(layout)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec())
python
import sys
from PySide6.QtWidgets import (
QApplication,
QMenu,
QPushButton,
QVBoxLayout,
QWidget,
)
class Window(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.btnOne = QPushButton(text="Menu!", parent=self)
self.menu = QMenu(self)
self.menu.addAction("First Item")
self.menu.addAction("Second Item")
self.menu.addAction("Third Item")
self.btnOne.setMenu(self.menu)
layout = QVBoxLayout()
layout.addWidget(self.btnOne)
self.setLayout(layout)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec())
In this example, we create a button with an associated popup menu. To attach the menu to the target button, we use setMenu()
, which turns the button into a menu button.
If you run this application, then you’ll get a window that will look something like this:
Window with a single button, with attached drop-down menu.
In some window styles, the button will show a small triangle on the right end of the button. If we click the button, then the pop-up menu will appear, allowing us to select any available menu option.
Conclusion
Push buttons are pretty useful widgets in any GUI application. Buttons can respond to the user’s events and perform actions in our applications.
In this tutorial, you’ve learned how to create, use, and customize your button while building a GUI application.
К старту курса по разработке на Python делимся детальным руководством по работе с современным PyQt. Чтобы читать было удобнее, мы объединили несколько статей в одну:
-
Первое приложение
-
Слоты и сигналы
-
Виджеты
За подробностями приглашаем под кат.
Простое приложение Hello World! на Python и Qt6
PyQt — это библиотека Python для создания приложений с графическим интерфейсом с помощью инструментария Qt. Созданная в Riverbank Computing, PyQt является свободным ПО (по лицензии GPL) и разрабатывается с 1999 года. Последняя версия PyQt6 — на основе Qt 6 — выпущена в 2021 году, и библиотека продолжает обновляться. Это руководство можно также использовать для PySide2, PySide6 и PyQt5.
Сегодня используются две основные версии: PyQt5 на основе Qt5 и PyQt6 на основе Qt6. Обе почти полностью совместимы, за исключением импорта и отсутствия поддержки некоторых продвинутых модулей из Qt6. В PyQt6 вносятся изменения в работу пространств имён и флагов, но ими легко управлять. В этом руководстве мы узнаем, как использовать PyQt6 для создания настольных приложений.
Сначала создадим несколько простых окон на рабочем столе, чтобы убедиться, что PyQt работает, и разберём базовые понятия. Затем кратко изучим цикл событий и то, как он связан с программированием графического интерфейса на Python. В заключение поговорим о QMainWindow с полезными элементами интерфейса, такими как панели инструментов и меню. Подробно я расскажу о них в следующих руководствах.
Создание приложения
Установка PyQt:
pip install pyqt6
# и на будущее
pip install pyqt-tools
Сначала создадим новый файл Python с любым названием (например app.py) и сохраним его. Исходный код приложения показан ниже. Введите его полностью и постарайтесь не ошибиться. Если что-то напутаете, Python укажет, что именно:
from PyQt6.QtWidgets import QApplication, QWidget
import sys # Только для доступа к аргументам командной строки
# Приложению нужен один (и только один) экземпляр QApplication.
# Передаём sys.argv, чтобы разрешить аргументы командной строки для приложения.
# Если не будете использовать аргументы командной строки, QApplication([]) тоже работает
app = QApplication(sys.argv)
# Создаём виджет Qt — окно.
window = QWidget()
window.show() # Важно: окно по умолчанию скрыто.
# Запускаем цикл событий.
app.exec()
# Приложение не доберётся сюда, пока вы не выйдете и цикл
# событий не остановится.
Запускаем приложение из командной строки, как и любой скрипт Python:
python3 app.py
Выполнив его, мы увидим окно. В Qt автоматически создаётся окно с обычным оформлением, возможностью его перетаскивать и менять размер. То, что вы увидите, зависит от платформы, где этот пример выполняется. Вот как отображается это окно на Windows, macOS и Linux (Ubuntu):
Разбор кода
Пройдём код построчно, чтобы понять, что именно происходит. Сначала мы импортируем классы PyQt для приложения: здесь это обработчик приложения QApplication и базовый пустой виджет графического интерфейса QWidget (оба из модуля QtWidgets):
from PyQt6.QtWidgets import QApplication, QWidget
Основные модули для Qt: QtWidgets, QtGui и QtCore.
Возможен ещё from import *
, но этот вид импорта обычно не приветствуется в Python. Дальше создаём экземпляр QApplication и передаём sys.arg (список Python с аргументами командной строки, передаваемыми приложению):
app = QApplication(sys.argv)
Если не будете использовать аргументы командной строки для управления Qt, передайте пустой список:
app = QApplication([])
Затем создаём экземпляр QWidget, используя имя переменной window:
window = QWidget()
window.show()
В Qt все виджеты верхнего уровня — окна, то есть у них нет родительского элемента и они не вложены в другой виджет или макет. В принципе, окно можно создать, используя любой виджет.
Виджеты без родительского элемента по умолчанию невидимы. Поэтому после создания объекта window необходимо всегда вызывать функцию .show(), чтобы сделать его видимым. .show() можно удалить, но тогда, запустив приложение, вы не сможете выйти из него!
В окне находится пользовательский интерфейс приложения. У каждого приложения он как минимум один. Приложение (по умолчанию) завершает работу при закрытии последнего окна.
Наконец, вызываем app.exec(), чтобы запустить цикл события.
Что такое «цикл событий»?
Прежде чем вывести окно на экран, разберём ключевые понятия, касающиеся организации приложений в мире Qt. Если вам уже знакомы циклы событий, можете пропустить эту часть статьи.
Основной элемент всех приложений в Qt — класс QApplication. Для работы каждому приложению нужен один — и только один — объект QApplication, который содержит цикл событий приложения. Это основной цикл, управляющий всем взаимодействием пользователя с графическим интерфейсом:
При каждом взаимодействии с приложением — будь то нажатие клавиши, щелчок или движение мыши — генерируется событие, которое помещается в очередь событий. В цикле событий очередь проверяется на каждой итерации: если найдено ожидающее событие, оно вместе с управлением передаётся определённому обработчику этого события. Последний обрабатывает его, затем возвращает управление в цикл событий и ждёт новых событий. Для каждого приложения выполняется только один цикл событий.
Класс QApplication содержит цикл событий Qt (нужен один экземпляр QApplication). Приложение ждёт в цикле событий новое событие, которое будет сгенерировано при выполнении действия. Всегда выполняется только один цикл событий.
QMainWindow
Итак, в Qt любые виджеты могут быть окнами. Например, если заменить QtWidget на QPushButton. В этом примере получается окно с одной нажимаемой кнопкой:
import sys
from PyQt6.QtWidgets import QApplication, QPushButton
app = QApplication(sys.argv)
window = QPushButton("Push Me")
window.show()
app.exec()
Классно, но не очень полезно на самом деле: редко когда нужен пользовательский интерфейс, состоящий только из одного элемента управления. Зато возможность с помощью макетов вкладывать одни виджеты в другие позволяет создавать сложные пользовательские интерфейсы внутри пустого QWidget.
В Qt уже есть решение для окна — виджет QMainWindow, имеющий стандартные функции окна для использования в приложениях, который содержит панели инструментов, меню, строку состояния, закрепляемые виджеты и многое другое. Рассмотрим эти расширенные функции позже, а пока добавим в приложение простой, пустой QMainWindow:
import sys
from PyQt6.QtWidgets import QApplication, QMainWindow
app = QApplication(sys.argv)
window = QMainWindow()
window.show()
# Запускаем цикл событий.
app.exec()
Запускаем и видим главное окно. Точно такое же, как и раньше.
QMainWindow пока не очень интересный. Добавим контент. Чтобы сделать настраиваемое окно, лучше создать подкласс QMainWindow, а затем настроить окно в блоке __init__. Так окно станет независимым в плане поведения. Итак, добавляем подкласс QMainWindow — MainWindow:
import sys
from PyQt6.QtCore import QSize, Qt
from PyQt6.QtWidgets import QApplication, QMainWindow, QPushButton
# Подкласс QMainWindow для настройки главного окна приложения
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("My App")
button = QPushButton("Press Me!")
# Устанавливаем центральный виджет Window.
self.setCentralWidget(button)
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()
Для этого демо используем QPushButton. Основные виджеты Qt всегда импортируются из пространства имён QtWidgets, как и классы QMainWindow и QApplication. При использовании QMainWindow задействуем .setCentralWidget для размещения виджета (здесь виджет — QPushButton) в QMainWindow, по умолчанию он занимает всё окно. Как добавлять в окна несколько виджетов? Об этом поговорим рассмотрим в руководстве по макетам.
При создании подкласса из класса Qt, чтобы разрешить Qt настраивать объект, всегда нужно вызывать функцию super __init__.
В блоке __init__ сначала используем .setWindowTitle(), чтобы поменять заголовок главного окна. Затем добавляем первый виджет — QPushButton — в середину окна. Это один из основных виджетов Qt. При создании кнопки можно ввести текст, который будет на ней отображаться. Вызываем .setCentralWidget() в окне. Это специальная функция QMainWindow, которая позволяет установить виджет на середину окна.
Запускаем и снова видим окно, но на этот раз с виджетом QPushButton в центре. Нажатие кнопки ничего не даст — с этим мы разберёмся после:
Скоро мы подробно рассмотрим другие виджеты, но, если вам не терпится и хочется забежать вперёд, можете заглянуть в документацию QWidget. Попробуйте добавить различные виджеты в окно.
Изменение размеров окон и виджетов
Сейчас размер окна можно свободно поменять: щёлкните мышью на любой угол и перетаскивайте, меняя таким образом размер. Можно дать возможность пользователям самим менять размер приложений, а можно установить ограничения на минимальные или максимальные размеры или фиксированный размер окна.
В Qt размеры определяются с помощью объекта QSize. Он принимает параметры ширины и высоты. Например, так создаётся окно фиксированного размера 400 x 300 пикселей:
import sys
from PyQt6.QtCore import QSize, Qt
from PyQt6.QtWidgets import QApplication, QMainWindow, QPushButton
# Подкласс QMainWindow для настройки главного окна приложения
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("My App")
button = QPushButton("Press Me!")
self.setFixedSize(QSize(400, 300))
# Устанавливаем центральный виджет Window.
self.setCentralWidget(button)
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()
Запускаем и видим окно фиксированного размера. Поменять его размер не получится.
Элемент управления maximize отключён на Windows и Linux. На macOS можно развернуть приложение на весь экран, но размер центрального виджета не изменится.
Кроме .setFixedSize() можно также вызвать .setMinimumSize() и .setMaximumSize(), чтобы установить минимальный и максимальный размеры соответственно. Попробуйте сами! Эти методы регулирования размеров работают в любом виджете. Продолжить изучение Python вы сможете на наших курсах:
-
Курс Python-разработчик
-
Профессия Fullstack-разработчик на Python
-
Курс «Python для веб-разработки»
А ещё вы можете приобрести книгу автора этих уроков или продолжить чтение.
Слоты и сигналы
Ранее мы рассмотрели классы QApplication и QMainWindow, цикл событий и добавили в окно простой виджет. А теперь изучим механизмы Qt для взаимодействия виджетов и окон друг с другом. В статью внесены изменения, связанные с PyQt6.
Мы создали окно и добавили в него простой виджет push button, но кнопка пока бесполезна. Нужно связать действие нажатия кнопки с происходящим. В Qt это делается с помощью сигналов и слотов или событий.
Сигналы — это уведомления, отправляемые виджетами, когда что-то происходит. Этим «чем-то» может быть что угодно — нажатие кнопки, изменение текста в поле ввода или изменение текста в окне. Многие сигналы инициируются в ответ на действия пользователя, но не только: в сигналах могут отправляться данные с дополнительным контекстом произошедшего.
Можно также писать собственные сигналы, их мы рассмотрим позже.
Слоты в Qt — это приёмники сигналов. Слотом в приложении на Python можно сделать любую функцию (или метод), просто подключив к нему сигнал. Принимающая функция получает данные, отправляемые ей в сигнале. У многих виджетов Qt есть встроенные слоты, а значит, виджеты можно подключать друг к другу напрямую.
Рассмотрим основные сигналы Qt и их использование для подключения виджетов в приложениях. Сохраните эту заготовку приложения в файле app.py:
import sys
from PyQt6.QtWidgets import QApplication, QMainWindow, QPushButton
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.setWindowTitle("My App")
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()
Сигналы QPushButton
Сейчас у нас есть QMainWindow с центральным виджетом QPushButton. Подключим эту кнопку к пользовательскому методу Python. Создадим простой настраиваемый слот the_button_was_clicked, принимающий сигнал clicked от QPushButton:
import sys
from PyQt6.QtWidgets import QApplication, QMainWindow, QPushButton
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("My App")
button = QPushButton("Press Me!")
button.setCheckable(True)
button.clicked.connect(self.the_button_was_clicked)
# Устанавливаем центральный виджет Window.
self.setCentralWidget(button)
def the_button_was_clicked(self):
print("Clicked!")
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()
Запускаем. Если нажать на кнопку, в консоли появится текст Clicked! («Нажата!»):
Clicked!
Clicked!
Clicked!
Clicked!
Получение данных
В сигналах может отправляться дополнительная информация о произошедшем. И сигнал .clicked — не исключение: с его помощью сообщается о нажатом (или переключенном) состоянии кнопки. Для обычных кнопок это значение всегда False, поэтому первый слот проигнорировал эти данные. Включим возможность нажатия кнопки, чтобы увидеть этот эффект. Ниже добавляется второй слот и выводится состояние нажатия:
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("My App")
button = QPushButton("Press Me!")
button.setCheckable(True)
button.clicked.connect(self.the_button_was_clicked)
button.clicked.connect(self.the_button_was_toggled)
self.setCentralWidget(button)
def the_button_was_clicked(self):
print("Clicked!")
def the_button_was_toggled(self, checked):
print("Checked?", checked)
Запускаем! Если нажать на кнопку, она подсветится и станет checked («Нажатой»). Чтобы отключить её, нажимаем ещё раз. Найдите состояние нажатия в консоли:
Clicked!
Checked? True
Clicked!
Checked? False
Clicked!
Checked? True
Clicked!
Checked? False
Clicked!
Checked? True
К сигналу подключается сколько угодно слотов, в которых можно реагировать сразу на несколько версий сигналов.
Хранение данных
Текущее состояние виджета на Python часто хранят в переменной, что позволяет работать со значениями без доступа к исходному виджету. Причём для их хранения используются отдельные переменные или словарь. В следующем примере сохраняем значение кнопки checked («Нажата») в переменной button_is_checked в self:
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.button_is_checked = True
self.setWindowTitle("My App")
button = QPushButton("Press Me!")
button.setCheckable(True)
button.clicked.connect(self.the_button_was_toggled)
button.setChecked(self.button_is_checked)
self.setCentralWidget(button)
def the_button_was_toggled(self, checked):
self.button_is_checked = checked
print(self.button_is_checked)
Сначала устанавливаем переменной значение по умолчанию True, а затем используем это значение, чтобы установить исходное состояние виджета. Когда состояние виджета меняется, получаем сигнал и соответственно обновляем переменную.
Эта же схема применима к любым виджетам PyQt. Если в виджете нет сигнала, которым отправляется текущее состояние, нужно получить значение из виджета прямо в обработчике. Например, здесь мы проверяем состояние checked («Нажата») в нажатом обработчике:
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.button_is_checked = True
self.setWindowTitle("My App")
self.button = QPushButton("Press Me!")
self.button.setCheckable(True)
self.button.released.connect(self.the_button_was_released)
self.button.setChecked(self.button_is_checked)
self.setCentralWidget(self.button)
def the_button_was_released(self):
self.button_is_checked = self.button.isChecked()
print(self.button_is_checked)
Сохраним ссылку на кнопку в self, чтобы получить к ней доступ в слоте.
Сигнал released срабатывает, когда кнопка отпускается, при этом состояние нажатия не отправляется. Его получают из кнопки в обработчике, используя .isChecked().
Изменение интерфейса
Мы уже видели, как принимаются сигналы и выводятся на консоль результаты. Но что происходит с интерфейсом, когда нажимают на кнопку? Обновим метод слота, чтобы изменить кнопку, поменяв текст, отключив её и сделав её недоступной. И отключим пока состояние, допускающее нажатие:
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("My App")
self.button = QPushButton("Press Me!")
self.button.clicked.connect(self.the_button_was_clicked)
self.setCentralWidget(self.button)
def the_button_was_clicked(self):
self.button.setText("You already clicked me.")
self.button.setEnabled(False)
# Также меняем заголовок окна.
self.setWindowTitle("My Oneshot App")
Снова нужен доступ к кнопке в методе the_button_was_clicked, поэтому сохраняем ссылку на неё в self. Чтобы поменять текст кнопки, передаём str в .setText(). Чтобы отключить кнопку, вызываем .setEnabled() с аргументом False. И запускаем программу. Если нажать на кнопку, текст изменится и кнопка станет недоступной.
В методах слота можно не только менять кнопку, которая активирует сигнал, но и делать всё что угодно. Например, поменять заголовок окна, добавив в метод the_button_was_clicked эту строку:
self.setWindowTitle("A new window title")
Большинство виджетов, в том числе QMainWindow, имеют свои сигналы. В следующем, более сложном примере подключим сигнал .windowTitleChanged в QMainWindow к пользовательскому методу слота. А также сделаем для этого слота новый заголовок окна:
from PyQt6.QtWidgets import QApplication, QMainWindow, QPushButton
import sys
from random import choice
window_titles = [
'My App',
'My App',
'Still My App',
'Still My App',
'What on earth',
'What on earth',
'This is surprising',
'This is surprising',
'Something went wrong'
]
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.n_times_clicked = 0
self.setWindowTitle("My App")
self.button = QPushButton("Press Me!")
self.button.clicked.connect(self.the_button_was_clicked)
self.windowTitleChanged.connect(self.the_window_title_changed)
# Устанавливаем центральный виджет Window.
self.setCentralWidget(self.button)
def the_button_was_clicked(self):
print("Clicked.")
new_window_title = choice(window_titles)
print("Setting title: %s" % new_window_title)
self.setWindowTitle(new_window_title)
def the_window_title_changed(self, window_title):
print("Window title changed: %s" % window_title)
if window_title == 'Something went wrong':
self.button.setDisabled(True)
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()
Сначала создаём список заголовков окна и выбираем один из них наугад, используя встроенную функцию Python random.choice(). Подключаем пользовательский метод слота the_window_title_changed к сигналу окна .windowTitleChanged.
При нажатии на кнопку заголовок окна случайным образом изменится. Если новый заголовок окна изменится на Something went wrong («Что-то пошло не так»), кнопка отключится.
Запускаем! Нажимайте на кнопку, пока заголовок не изменится на Something went wrong. В этом примере стоит обратить внимание вот на что:
-
Сигнал windowTitleChanged при установке заголовка окна выдаётся не всегда. Он срабатывает, только если новый заголовок отличается от предыдущего: если один и тот же заголовок устанавливается несколько раз, сигнал срабатывает только в первый раз. Чтобы избежать неожиданностей, важно перепроверять условия срабатывания сигналов при их использовании в приложении.
-
С помощью сигналов создаются цепочки. Одно событие — нажатие кнопки — может привести к тому, что поочерёдно произойдут другие. Эти последующие эффекты отделены от того, что их вызвало. Они возникают согласно простым правилам. И это отделение эффектов от их триггеров — один из ключевых принципов, которые учитываются при создании приложений с графическим интерфейсом. Возвращаться к этому будем на протяжении всего курса.
Мы рассмотрели сигналы и слоты, показали простые сигналы и их использование для передачи данных и состояния в приложении. Теперь переходим к виджетам Qt, которые будут использоваться в приложениях вместе с сигналами.
Подключение виджетов друг к другу напрямую
Мы уже видели примеры подключения сигналов виджетов к методам Python. Когда сигнал из виджета срабатывает, вызывается метод Python, из сигнала он получает данные. Но для обработки сигналов не всегда нужна функция Python — можно подключать виджеты друг к другу напрямую.
Добавим в окно виджеты QLineEdit и QLabel. В __init__ для окна и подключим сигнал редактирования строки .textChanged к методу .setText в QLabel. Когда в QLineEdit меняется текст, он сразу будет поступать в QLabel (в метод .setText):
from PyQt6.QtWidgets import QApplication, QMainWindow, QLabel, QLineEdit, QVBoxLayout, QWidget
import sys
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("My App")
self.label = QLabel()
self.input = QLineEdit()
self.input.textChanged.connect(self.label.setText)
layout = QVBoxLayout()
layout.addWidget(self.input)
layout.addWidget(self.label)
container = QWidget()
container.setLayout(layout)
# Устанавливаем центральный виджет Window.
self.setCentralWidget(container)
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()
Внимание: чтобы подключить входные данные к метке, нужно определить и эти данные, и метку. В этом коде в макет добавляются два виджета и устанавливаются в окне. Подробно рассмотрим макеты позже, а пока не обращайте на них внимания.
Запускаем программу:
Введите текст в верхнем поле — он сразу появится в виде метки.
У большинства виджетов Qt есть доступные слоты, к которым подключается любой сигнал, возврощающий тот же тип, что он принимает. В документации по виджетам, в разделе Public Slots («Общедоступные слоты»), имеются слоты для каждого виджета. Посмотрите документацию для QLabel.
События
Любое взаимодействие пользователя с приложением Qt — это событие. Есть много типов событий, каждое из которых — это отдельный тип взаимодействия. В Qt события представлены объектами событий, в которые упакована информация о произошедшем. События передаются определённым обработчикам событий в виджете, где произошло взаимодействие.
Определяя пользовательские или расширенные обработчики событий, можно менять способ реагирования виджетов на них. Обработчики событий определяются так же, как и любой другой метод, но название обработчика зависит от типа обрабатываемого события.
QMouseEvent — одно из основных событий, получаемых виджетами. События QMouseEvent создаются для каждого отдельного нажатия кнопки мыши и её перемещения в виджете. Вот обработчики событий мыши:
Обработчик |
Событие |
---|---|
|
Мышь переместилась |
|
Кнопка мыши нажата |
|
Кнопка мыши отпущена |
|
Обнаружен двойной клик |
Например, нажатие на виджет приведёт к отправке QMouseEvent в обработчик событий .mousePressEvent в этом виджете.
События можно перехватывать, создав подкласс и переопределив метод обработчика в этом классе. Их можно фильтровать, менять или игнорировать, передавая обычному обработчику путём вызова функции суперкласса методом super(). Они добавляются в класс главного окна следующим образом (в каждом случае в e будет получено входящее событие):
import sys
from PyQt6.QtCore import Qt
from PyQt6.QtWidgets import QApplication, QLabel, QMainWindow, QTextEdit
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.label = QLabel("Click in this window")
self.setCentralWidget(self.label)
def mouseMoveEvent(self, e):
self.label.setText("mouseMoveEvent")
def mousePressEvent(self, e):
self.label.setText("mousePressEvent")
def mouseReleaseEvent(self, e):
self.label.setText("mouseReleaseEvent")
def mouseDoubleClickEvent(self, e):
self.label.setText("mouseDoubleClickEvent")
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()
Запускаем! В окне переместите мышь и нажмите на кнопку, затем дважды нажмите на кнопку и посмотрите, какие появляются события.
События перемещения мыши регистрируются только при нажатой кнопке. Чтобы это изменить, вызовите в окне self.setMouseTracking(True). События press («Нажатие кнопки»), click («Клика») и double-click («Двойного клика») срабатывают при нажатии кнопки. Событие release («Отпускание») срабатывает, только когда кнопка отпускается. Клик пользователя регистрируется обычно при нажатии кнопки мыши и её отпускании.
Внутри обработчиков события есть доступ к объекту этого события. Он содержит информацию о событии и используется, чтобы реагировать по-разному в зависимости от того, что произошло. Рассмотрим объекты событий управления мышью.
События управления мышью
В Qt все события управления мышью отслеживаются с помощью объекта QMouseEvent. При этом информация о событии считывается из следующих методов событий:
Метод |
Возвращает |
---|---|
|
Конкретную кнопку, вызвавшую данное событие |
|
Состояние всех кнопок мыши (флаги OR) |
|
Относительную позицию виджета в виде целого |
Эти методы используются в обработчике событий, чтобы на разные события реагировать по-разному или полностью их игнорировать. Через методы позиционирования в виде объектов QPoint предоставляется глобальная и локальная (касающаяся виджета) информация о местоположении. Сведения о кнопках поступают с использованием типов кнопок мыши из пространства имён Qt. Например, в этом коде показаны разные реакции на нажатие левой, правой или средней кнопки мыши в окне:
def mousePressEvent(self, e):
if e.button() == Qt.LeftButton:
# здесь обрабатываем нажатие левой кнопки
self.label.setText("mousePressEvent LEFT")
elif e.button() == Qt.MiddleButton:
# здесь обрабатываем нажатие средней кнопки.
self.label.setText("mousePressEvent MIDDLE")
elif e.button() == Qt.RightButton:
# здесь обрабатываем нажатие правой кнопки.
self.label.setText("mousePressEvent RIGHT")
def mouseReleaseEvent(self, e):
if e.button() == Qt.LeftButton:
self.label.setText("mouseReleaseEvent LEFT")
elif e.button() == Qt.MiddleButton:
self.label.setText("mouseReleaseEvent MIDDLE")
elif e.button() == Qt.RightButton:
self.label.setText("mouseReleaseEvent RIGHT")
def mouseDoubleClickEvent(self, e):
if e.button() == Qt.LeftButton:
self.label.setText("mouseDoubleClickEvent LEFT")
elif e.button() == Qt.MiddleButton:
self.label.setText("mouseDoubleClickEvent MIDDLE")
elif e.button() == Qt.RightButton:
self.label.setText("mouseDoubleClickEvent RIGHT")
Идентификаторы кнопок определяются в пространстве имён Qt:
Код |
Бинарное значение |
Описание |
---|---|---|
|
0 ( |
Кнопка не нажата, или событие не связано с нажатием кнопки |
|
1 ( |
Левая кнопка нажата |
|
2 ( |
Правая кнопка нажата |
|
4 ( |
Средняя кнопка [обычно это колёсико мыши] нажата |
В мышках для правшей положения левой и правой кнопок меняются местами, то есть при нажатии правой кнопки вернётся Qt.LeftButton. Иными словами, учитывать ориентацию мыши не нужно.
Контекстные меню
Контекстные меню — это небольшие контекстно-зависимые меню, которые обычно появляются в окне при нажатии правой кнопкои мыши. В Qt у виджетов есть определённое событие для активации таких меню.
В примере ниже мы будем перехватывать событие .contextMenuEvent в QMainWindow. Это событие запускается всякий раз перед самым появлением контекстного меню, а передаётся событие с одним значением типа QContextMenuEvent.
Чтобы перехватить событие, просто переопределяем метод объекта с помощью нового метода с тем же именем. В нашем случае создаём метод в подклассе MainWindow с именем contextMenuEvent, и он будет получать все события этого типа:
import sys
from PyQt6.QtCore import Qt
from PyQt6.QtGui import QAction
from PyQt6.QtWidgets import QApplication, QLabel, QMainWindow, QMenu
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
def contextMenuEvent(self, e):
context = QMenu(self)
context.addAction(QAction("test 1", self))
context.addAction(QAction("test 2", self))
context.addAction(QAction("test 3", self))
context.exec(e.globalPos())
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()
Если запустить этот код и нажать правой кнопкой в окне, появится контекстное меню. В действиях меню можно настроить слоты .triggered как обычные (и повторно использовать действия, определённые для меню и панелей инструментов).
При передаче исходного положения в функцию exec оно должно соответствовать родительскому элементу, переданному при определении. В нашем случае в качестве родительского элемента передаётся self, поэтому используем глобальное положение. Для полноты картины нужно сказать, что создавать контекстные меню можно и при помощи сигналов:
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.show()
self.setContextMenuPolicy(Qt.CustomContextMenu)
self.customContextMenuRequested.connect(self.on_context_menu)
def on_context_menu(self, pos):
context = QMenu(self)
context.addAction(QAction("test 1", self))
context.addAction(QAction("test 2", self))
context.addAction(QAction("test 3", self))
context.exec(self.mapToGlobal(pos))
Что выбрать — решать только вам.
Иерархия событий
В PyQt каждый виджет — это часть двух различных иерархий: иерархии объектов в Python и иерархии макета в Qt. Реакция на события или их игнорирование влияет на поведение пользовательского интерфейса.
Перенаправление наследования Python
Часто бывает нужно перехватить событие, что-то с ним сделать, запустив при этом поведение обработки событий по умолчанию. Если объект унаследован от стандартного виджета, у него наверняка будет поведение по умолчанию. Запустить его можно, методом super() вызвав реализацию из суперкласса. Будет вызван именно суперкласс в Python, а не .parent() из PyQt:
def mousePressEvent(self, event):
print("Mouse pressed!")
super(self, MainWindow).contextMenuEvent(event)
Интерфейс ведёт себя как раньше, при этом мы добавили новое поведение, которое не вмешивается в прежнее.
Передача вверх по иерархии макета
Когда в приложение добавляется виджет, он также получает из макета другой родительский элемент. Чтобы найти родительский элемент виджета, надо вызвать функцию .parent(). Иногда эти родительские элементы указываются вручную (и часто автоматически), например для QMenu или QDialog. Когда в главное окно добавляется виджет, оно становится родительским элементом виджета.
Когда события создаются для взаимодействия пользователя с пользовательским интерфейсом, они передаются в его самый верхний виджет. Если в окне есть кнопка и вы нажмёте её, она получит событие первой.
Если первый виджет не может обработать событие, оно перейдёт к следующему по очереди родительскому виджету. Эта передача вверх по иерархии вложенных виджетов продолжится, пока событие не будет обработано или не достигнет главного окна. В обработчиках событий событие помечают как обработанное через вызов .accept():
class CustomButton(QPushButton)
def mousePressEvent(self, e):
e.accept()
Вызвав в объекте события .ignore(), помечают его как необработанное. В этом случае событие будет передаваться по иерархии вверх:
class CustomButton(QPushButton)
def event(self, e):
e.ignore()
Чтобы виджет пропускал события, вы можете спокойно игнорировать те, на которые каким-то образом реагировали. Аналогично вы можете отреагировать на одни события, заглушая другие. А продолжить изучение Python вы сможете на наших курсах:
-
Курс Python-разработчик
-
Профессия Fullstack-разработчик на Python
-
Курс «Python для веб-разработки»
Напомним также о книге автора этих уроков.
Виджеты
В большинстве пользовательских интерфейсов и в Qt «виджет» — это компонент, с которым взаимодействует пользователь. Пользовательские интерфейсы состоят из нескольких виджетов, расположенных внутри окна. В Qt большой выбор виджетов и можно создать собственные виджеты.
Краткое демо
Посмотрим на самые распространённые виджеты PyQt. Они создаются и добавляются в макет окна с помощью этого кода (работу макетов в Qt рассмотрим в следующем руководстве):
import sys
from PyQt6.QtCore import Qt
from PyQt6.QtWidgets import (
QApplication,
QCheckBox,
QComboBox,
QDateEdit,
QDateTimeEdit,
QDial,
QDoubleSpinBox,
QFontComboBox,
QLabel,
QLCDNumber,
QLineEdit,
QMainWindow,
QProgressBar,
QPushButton,
QRadioButton,
QSlider,
QSpinBox,
QTimeEdit,
QVBoxLayout,
QWidget,
)
# Подкласс QMainWindow для настройки основного окна приложения
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("Widgets App")
layout = QVBoxLayout()
widgets = [
QCheckBox,
QComboBox,
QDateEdit,
QDateTimeEdit,
QDial,
QDoubleSpinBox,
QFontComboBox,
QLCDNumber,
QLabel,
QLineEdit,
QProgressBar,
QPushButton,
QRadioButton,
QSlider,
QSpinBox,
QTimeEdit,
]
for w in widgets:
layout.addWidget(w())
widget = QWidget()
widget.setLayout(layout)
# Устанавливаем центральный виджет окна. Виджет будет расширяться по умолчанию,
# заполняя всё пространство окна.
self.setCentralWidget(widget)
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()
Запускаем! Появится окно со всеми созданными виджетами:
Посмотрим внимательно на все эти виджеты:
Класс виджета |
Описание виджета |
---|---|
|
Чекбокс |
|
Окно выпадающего списка |
|
Для редактирования даты и времени |
|
Для редактирования даты и времени |
|
Поворотный циферблат |
|
Спиннер для чисел с плавающей точкой |
|
Список шрифтов |
|
Довольно неприятный дисплей LCD |
|
Просто метка, не интерактивная |
|
Поле ввода со строкой |
|
Индикатор выполнения |
|
Кнопка |
|
Переключаемый набор, в котором активен только один элемент |
|
Слайдер |
|
Спиннер для целых чисел |
|
Поле редактирования времени |
Их гораздо больше, но они не поместятся в статью. Полный список есть в документации Qt.
Разберём подробно самые используемые виджеты и поэкспериментируем с ними в простом приложении. Сохраните следующий код в файле app.py и, запустив его, убедитесь, что он работает:
import sys
from PyQt6.QtWidgets import (
QMainWindow, QApplication,
QLabel, QCheckBox, QComboBox, QListBox, QLineEdit,
QLineEdit, QSpinBox, QDoubleSpinBox, QSlider
)
from PyQt6.QtCore import Qt
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.setWindowTitle("My App")
app = QApplication(sys.argv)
w = MainWindow()
w.show()
app.exec()
Выше мы импортировали несколько виджетов Qt. Разберём каждый по очереди. Добавим их в приложение и посмотрим, как они себя ведут.
QLabel
Начнём с QLabel, одного из простейших виджетов в Qt. Он состоит из строчки текста и устанавливается в приложении. Текст задаётся аргументом QLabel:
widget = QLabel("Hello")
Или с помощью метода .setText():
widget = QLabel("1") # Создана метка с текстом 1.
widget.setText("2") # Создана метка с текстом 2.
Параметры шрифта, например его размер или выравнивание в виджете, настраиваются так:
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.setWindowTitle("My App")
widget = QLabel("Hello")
font = widget.font()
font.setPointSize(30)
widget.setFont(font)
widget.setAlignment(Qt.AlignmentFlag.AlignHCenter | Qt.AlignmentFlag.AlignVCenter)
self.setCentralWidget(widget)
Рекомендация по шрифту: чтобы изменить свойства шрифта виджета, лучше получить текущий шрифт, обновить его и применить снова. Так начертание шрифта будет соответствовать ограничениям рабочего стола. Выравнивание указывается с помощью флага из пространства имён Qt. Вот флаги для горизонтального выравнивания:
Флаг PyQt6 (полный код) |
Поведение |
---|---|
|
Выравнивает по левому краю |
|
Выравнивает по правому краю |
|
Центрирует по горизонтали в доступном пространстве |
|
Выравнивает текст в доступном пространстве |
Флаги используются вместе с помощью каналов (|), но флаги вертикального и горизонтального выравнивания не применяются одновременно:
Флаг PyQt6 (полный код) |
Поведение |
---|---|
|
Выравнивается по верху |
|
Выравнивается по низу |
|
Центрирует вертикально в доступном пространстве |
align_top_left = Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignTop
При этом для совместного применения двух флагов (не A & B) используется канал | с операцией логического «ИЛИ». Эти флаги — неперекрывающиеся битовые маски. Например, у Qt.AlignmentFlag.AlignLeft шестнадцатеричное значение 0x0001, а у Qt.AlignmentFlag.AlignBottom — 0x0040. С помощью операции логического «ИЛИ» получаем значение «внизу слева» — 0x0041. Этот принцип применим и ко всем остальным парам флагов Qt. Если вам что-то здесь непонятно, смело пропускайте эту часть и переходите к следующей. Только не забывайте использовать |. Наконец, есть флаг, с помощью которого выполняется выравнивание по центру в обоих направлениях одновременно:
Флаг PyQt6 |
Поведение |
---|---|
|
Центрирует горизонтально и вертикально. |
Как ни странно, QLabel используется и для показа изображения с помощью .setPixmap(). Этот метод принимает QPixmap, создаваемый передачей имени файла изображения в QPixmap. Среди примеров из этой книги есть файл otje.jpg, который отображается в окне так:
widget.setPixmap(QPixmap('otje.jpg'))
Какая мордочка! По умолчанию изображение масштабируется, сохраняя соотношение ширины и высоты. Если нужно растянуть и подогнать его по размерам окна, установите .setScaledContents(True) в QLabel:
widget.setScaledContents(True)
QCheckBox
А этот виджет, как следует из названия, предоставляет пользователю чекбокс с флажками. Как и во всех виджетах Qt, здесь есть настраиваемые параметры, изменяющие его поведение:
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.setWindowTitle("My App")
widget = QCheckBox()
widget.setCheckState(Qt.CheckState.Checked)
# Включение трёх состояний: widget.setCheckState(Qt.PartiallyChecked)
# Или: widget.setTriState(True)
widget.stateChanged.connect(self.show_state)
self.setCentralWidget(widget)
def show_state(self, s):
print(s == Qt.CheckState.Checked)
print(s)
Состояние чекбокса устанавливается программно с помощью .setChecked или .setCheckState. Первый принимает True или False, то есть чекбокс с галочкой или без неё соответственно. В случае с .setCheckState с помощью флага пространства имён Qt также указывается конкретное состояние чекбокса:
Флаг PyQt6 (Полный код) |
Состояние |
---|---|
|
Элемент не отмечен |
|
Элемент отмечен частично |
|
Элемент отмечен |
Чекбокс, поддерживающий состояние частичной отмеченности (Qt.CheckState.PartiallyChecked) галочками, обычно называют «имеющим третье состояние», т. е. он и отмечен, и не отмечен. Чекбокс в этом состоянии часто отображается в виде серого флажка и используется в иерархических структурах чекбоксов, где дочерние чекбоксы связаны с родительскими.
Установив значение Qt.CheckState.PartiallyChecked, вы переведёте чекбокс в третье состояние. То же самое, но без перевода текущего состояния в состояние частичной отмеченности галочками, делается с помощью .setTriState(True).
При запуске скрипта номер текущего состояния отображается в виде значения целочисленного типа int. Причём состоянию, отмеченному галочками, соответствует 2, не отмеченному — 0, а состоянию частичной отмеченности — 1. Запоминать эти значения не нужно: К примеру, переменная пространства имён Qt.Checked равна 2. Это значение соответствующих флагов состояния. То есть вы можете проверить состояние с помощью state == Qt.Checked.
QComboBox
QComboBox — это выпадающий список, закрытый по умолчанию, с кнопкой, чтобы открыть его. Можно выбрать один элемент из списка, при этом выбранный в данный момент элемент отображается в виджете в виде метки. Поле со списком подходит для выбора варианта из длинного списка вариантов. Такое поле используется при выборе начертания или размера шрифта в текстовых редакторах. В Qt для выбора шрифта есть специальное поле со списком шрифтов — QFontComboBox.
В QComboBox можно добавлять элементы, передавая список строк в .addItems(). Элементы добавляются в порядке расположения соответствующих элементам строк кода.
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.setWindowTitle("My App")
widget = QComboBox()
widget.addItems(["One", "Two", "Three"])
# Отправляет текущий индекс (позицию) выбранного элемента.
widget.currentIndexChanged.connect( self.index_changed )
# Есть альтернативный сигнал отправки текста.
widget.textChanged.connect( self.text_changed )
self.setCentralWidget(widget)
def index_changed(self, i): # i — это int
print(i)
def text_changed(self, s): # s — это str
print(s)
Сигнал .currentIndexChanged срабатывает при обновлении выбранного в данный момент элемента, индекс которого в списке передаётся по умолчанию. Кроме того, есть сигнал .currentTextChanged, при срабатывании которого вместо индекса предоставляется метка выбранного в данный момент элемента. Это часто оказывается полезнее.
Также QComboBox можно редактировать, вводя значения, которых в данный момент нет в списке, — вставлять их или просто использовать как значения. Поле делается редактируемым так:
widget.setEditable(True)
Чтобы определить, как обрабатываются вставляемые значения, устанавливается флаг. Флаги хранятся в самом классе QComboBox. Вот их список:
Флаг PyQt6 (полный код) |
Поведение |
---|---|
|
Не вставлять |
|
Вставить как первый элемент |
|
Заменить текущий выбранный элемент |
|
Вставить после последнего элемента |
|
Вставить после текущего элемента |
|
Вставить перед текущим элементом |
|
Вставить в алфавитном порядке |
Чтобы использовать их, применяется флаг:
widget.setInsertPolicy(QComboBox.InsertPolicy.InsertAlphabetically)
Кроме того, можно ограничить количество элементов поля, например при помощи .setMaxCount:
widget.setMaxCount(10)
Подробнее о QComboBox рассказывается здесь.
QListWidget
Этот виджет похож на QComboBox, но варианты здесь представлены в виде прокручиваемого списка элементов и возможен выбор нескольких элементов одновременно. В QListWidget есть сигнал currentItemChanged для отправки QListItem (элемента виджета списка) и сигнал currentTextChanged для отправки текста текущего элемента:
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.setWindowTitle("My App")
widget = QListWidget()
widget.addItems(["One", "Two", "Three"])
widget.currentItemChanged.connect(self.index_changed)
widget.currentTextChanged.connect(self.text_changed)
self.setCentralWidget(widget)
def index_changed(self, i); # i — не индекс, а сам QList
print(i.text())
def text_changed(self, s): # s — это строка
print(s)
QLineEdit
Виджет QLineEdit — это простое однострочное текстовое поле для редактирования вводимых пользователями данных. Он используется для полей, где нет ограничений на входные данные. Например, при вводе адреса электронной почты или имени компьютера:
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.setWindowTitle("My App")
widget = QLineEdit()
widget.setMaxLength(10)
widget.setPlaceholderText("Enter your text")
#widget.setReadOnly(True) # раскомментируйте, чтобы сделать доступным только для чтения
widget.returnPressed.connect(self.return_pressed)
widget.selectionChanged.connect(self.selection_changed)
widget.textChanged.connect(self.text_changed)
widget.textEdited.connect(self.text_edited)
self.setCentralWidget(widget)
def return_pressed(self):
print("Return pressed!")
self.centralWidget().setText("BOOM!")
def selection_changed(self):
print("Selection changed")
print(self.centralWidget().selectedText())
def text_changed(self, s):
print("Text changed...")
print(s)
def text_edited(self, s):
print("Text edited...")
print(s)
Как показано в этом коде, при однострочном редактировании вы можете установить максимальную длину текста.
В QLineEdit есть ряд сигналов для различных событий редактирования, в том числе при нажатии клавиши return (пользователем), когда пользователь изменил свой выбор. Также есть два сигнала редактирования: один — на случай, когда текст в поле отредактирован, другой — когда он изменён. Здесь различаются два вида изменений: пользовательские и выполненные программой. Сигнал textEdited отправляется только при редактировании текста пользователем.
Кроме того, с помощью маски ввода можно выполнить проверку вводимых данных, чтобы определить, какие символы поддерживаются и где. Применяется к соответствующему полю так:
widget.setInputMask('000.000.000.000;_')
Это позволяет использовать серию трёхзначных чисел, разделённых точками, для проверки адресов IPv4.
QSpinBox и QDoubleSpinBox
QSpinBox — это небольшое поле ввода чисел со стрелками для изменения значения. Оно поддерживает целые числа, а QDoubleSpinBox — числа с плавающей точкой:
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("My App")
widget = QSpinBox()
# Или: widget = QDoubleSpinBox()
widget.setMinimum(-10)
widget.setMaximum(3)
# Или: widget.setRange(-10,3)
widget.setPrefix("$")
widget.setSuffix("c")
widget.setSingleStep(3) # Или, например, 0.5 в QDoubleSpinBox
widget.valueChanged.connect(self.value_changed)
widget.textChanged.connect(self.value_changed_str)
self.setCentralWidget(widget)
def value_changed(self, i):
print(i)
def value_changed_str(self, s):
print(s)
Запустив код, вы увидите поле для ввода чисел. Значение в нём показывает префиксные и постфиксные блоки и ограничено диапазоном от +3 до –10:
В этом коде показан разнообразный функционал виджета. Чтобы задать диапазон допустимых значений, используются setMinimum и setMaximum. Одновременно они устанавливаются с помощью SetRange. Аннотация типов значений поддерживается префиксами и суффиксами, добавляемыми к числу. Например, для обозначений валюты или денежных единиц используются .setPrefix и .setSuffix соответственно.
Нажав на стрелки «вверх» и «вниз» на виджете, можно увеличить или уменьшить значение на величину, устанавливаемую с помощью .setSingleStep. Но это не повлияет на допустимые для виджета значения.
В QSpinBox и QDoubleSpinBox есть сигнал .valueChanged, срабатывающий при изменении их значений. С помощью необработанного сигнала .valueChanged отправляется числовое значение (целочисленного типа int или типа числа с плавающей точкой float), а с помощью .textChanged — значение в виде строки, включающей символы префикса и суффикса.
QSlider
QSlider — это ползунок, очень схожий по внутреннему функционалу с QDoubleSpinBox. Текущее значение представлено не числами, а в виде маркера ползунка, располагающегося по всей длине виджета. Этот виджет удобен для указания значения в промежутке между максимумом и минимумом, где абсолютная точность не требуется. Чаще всего этот тип виджетов используется при регулировке громкости. Есть и другие сигналы: .sliderMoved срабатывает при перемещении ползунка а .sliderPressed — при нажатии на ползунок:
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("My App")
widget = QSlider()
widget.setMinimum(-10)
widget.setMaximum(3)
# Или: widget.setRange(-10,3)
widget.setSingleStep(3)
widget.valueChanged.connect(self.value_changed)
widget.sliderMoved.connect(self.slider_position)
widget.sliderPressed.connect(self.slider_pressed)
widget.sliderReleased.connect(self.slider_released)
self.setCentralWidget(widget)
def value_changed(self, i):
print(i)
def slider_position(self, p):
print("position", p)
def slider_pressed(self):
print("Pressed!")
def slider_released(self):
print("Released")
Запустив код, вы увидите ползунок. Переместите его, чтобы изменить значение:
Также можно сделать вертикальный или горизонтальный ползунок, задав соответствующее расположение при его создании. Флаги расположения определены в пространстве имён Qt, например:
widget.QSlider(Qt.Orientiation.Vertical)
Или так:
widget.QSlider(Qt.Orientiation.Horizontal)
QDial
Наконец, QDial — это круговой виджет, схожий по функционалу с механическим ползунком из реального мира. Красиво, но с точки зрения пользовательского интерфейса не очень удобно. Он часто используется в аудиоприложениях:
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("My App")
widget = QDial()
widget.setRange(-10, 100)
widget.setSingleStep(0.5)
widget.valueChanged.connect(self.value_changed)
widget.sliderMoved.connect(self.slider_position)
widget.sliderPressed.connect(self.slider_pressed)
widget.sliderReleased.connect(self.slider_released)
self.setCentralWidget(widget)
def value_changed(self, i):
print(i)
def slider_position(self, p):
print("position", p)
def slider_pressed(self):
print("Pressed!")
def slider_released(self):
print("Released")
Запустив код, вы увидите круговой ползунок. Поверните его, чтобы выбрать число:
На сегодня мы заканчиваем, но это далеко не всё. Мы также расскажем о макете в PyQt, о работе с QAction, тулбарами, диалогами и не только. А пока ещё раз напоминаем о книге автора этих уроков и приглашаем на наши курсы:
-
Курс Python-разработчик
-
Профессия Fullstack-разработчик на Python
-
Курс «Python для веб-разработки»
Узнайте подробности здесь.
Профессии и курсы
A button or command button is probably the most common widget in any graphical user interface.
Click the button to command the computer to perform an action or answer a question. Typical buttons are OK, apply, cancel, close, yes, no and help.
A button is rectangular and usually displays a text label that describes its actions. Shortcuts can be specified for buttons.
Related course: Create PyQt Desktop Appications with Python (GUI)
QPushButton
The button widget is called QPushButton. The QPushButton widget provides a default button.
Start by importing QPushButton into your Python script:
from PyQt5.QtWidgets import QPushButton
In the window constructor, add these lines which will add a button:
pybutton = QPushButton('Click me', self)
pybutton.resize(100,32)
pybutton.move(50, 50)
pybutton.clicked.connect(self.clickMethod)
The first line creates an object of the type QPushButton.
The first argument is the text shown on the button:
pybutton = QPushButton('Click me', self)
The appearance depends on the operating system and the configured theme, something like this:
We resize it to 100 pixels in width and 32 in height.
pybutton.resize(100,32)
Then we set it to position (50,50) on the window.
pybutton.move(50, 50)
The click must be linked to a Python method, clickMethod().
pybutton.clicked.connect(self.clickMethod)
pyqt5 button example
The program below creates a desktop window with a button inside of it.
By clicking the button it will call the method clickMethod().
The appearance of the window depends on the operating system.
import sys
from PyQt5 import QtCore, QtWidgets
from PyQt5.QtWidgets import QMainWindow, QLabel, QGridLayout, QWidget
from PyQt5.QtWidgets import QPushButton
from PyQt5.QtCore import QSize
class MainWindow(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
self.setMinimumSize(QSize(300, 200))
self.setWindowTitle("PyQt button example - pythonprogramminglanguage.com")
pybutton = QPushButton('Click me', self)
pybutton.clicked.connect(self.clickMethod)
pybutton.resize(100,32)
pybutton.move(50, 50)
def clickMethod(self):
print('Clicked Pyqt button.')
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
mainWin = MainWindow()
mainWin.show()
sys.exit( app.exec_() )
If you are new to Python PyQt, then I highly recommend this book.
PyQt Button example
The button can display a text label and can also select a small icon.
These can be set using constructor settings, which can be changed later using setText()
and setIcon()
.
If the button is disabled, the appearance of the text and icons is related to the GUI style to make the button look “disabled.”
self.button3.setEnabled(False)
When a button is activated by a mouse, space bar, or keyboard shortcut, the button sends a clicked() signal.
Connect to this signal to perform the action of the button. Buttons also provide less-used signals, such as pressed()
and released()
.
self.button3.clicked.connect(self.Action)
The program below shows various buttons in the window. It adds different types of buttons:
- Button 1 is a default button, a QPushButton
- Button 2 has a dropdown, by clicking it shows a menu QMenu
- Button 3 gets disabled for a few seconds and renabled using a QTimer
import sys
from PyQt5 import QtCore, QtWidgets
from PyQt5.QtWidgets import QMainWindow, QLabel, QGridLayout, QWidget, QMenu
from PyQt5.QtWidgets import QPushButton
from PyQt5.QtCore import QSize, QTimer
class Example(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
self.setMinimumSize(QSize(320, 200))
self.setWindowTitle("PyQt button example - pythonprogramminglanguage.com")
self.bt1 = QPushButton("Button 1",self)
self.bt2 = QPushButton("Button 2",self)
self.bt3 = QPushButton('Button 3',self)
self.bt1.move(50,50)
self.bt2.move(50,100)
self.bt3.move(170,100)
menu = QMenu(self)
menu.addAction('Fruit')
menu.addSeparator()
menu.addAction('Cookies')
menu.addSeparator()
menu.addAction('Ice cream')
self.bt2.setMenu(menu)
self.bt1.clicked.connect(self.Button1)
self.count = 10
self.bt3.clicked.connect(self.Action)
self.time = QTimer(self)
self.time.setInterval(1000)
self.time.timeout.connect(self.Refresh)
self.show()
def Button1(self):
print('Clicked')
def Action(self):
if self.bt3.isEnabled():
self.time.start()
self.bt3.setEnabled(False)
def Refresh(self):
if self.count > 0:
self.bt3.setText(str(self.count)+' seconds')
self.count -= 1
else:
self.time.stop()
self.bt3.setEnabled(True)
self.bt3.setText('Button 3')
self.count = 10
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
mainWin = Example()
mainWin.show()
sys.exit( app.exec_() )
In this example above, we implement three functions: menu buttons, buttons with countdowns (which are often encountered when accounts are registered) and a default click function.
The button menu QMenu is added to the button like this:
menu = QMenu(self)
menu.addAction('Fruit')
menu.addSeparator()
menu.addAction('Cookies')
menu.addSeparator()
menu.addAction('Ice cream')
self.bt2.setMenu(menu)
For the other example, we used the QTimer class, this is a time-related class.
The QTimer class provides repeatability and single timers. The QTimer class provides an advanced programming interface for timers.
To use it, create a QTimer, connect its timeout() signal to the appropriate slot, and then call start().
self.time = QTimer(self)
self.time.setInterval(1000)
self.time.timeout.connect(self.Refresh)
From then on, it will send out signals at regular intervals. SetInterval() This property has a time-out interval in milliseconds. The default value for this property is 0.
If you are new to Python PyQt, then I highly recommend this book.
Download PyQt Examples