Cannon Example¶
Simple Cannon example.
# PySide6 tutorial 6
import sys
from PySide6.QtCore import Qt
from PySide6.QtGui import QFont
from PySide6.QtWidgets import (QApplication, QGridLayout, QLCDNumber,
QPushButton, QSlider, QVBoxLayout, QWidget)
class LCDRange(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
lcd = QLCDNumber(2)
slider = QSlider(Qt.Horizontal)
slider.setRange(0, 99)
slider.setValue(0)
slider.valueChanged.connect(lcd.display)
layout = QVBoxLayout(self)
layout.addWidget(lcd)
layout.addWidget(slider)
class MyWidget(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
quit = QPushButton("Quit")
quit.setFont(QFont("Times", 18, QFont.Bold))
quit.clicked.connect(qApp.quit)
layout = QVBoxLayout(self)
layout.addWidget(quit)
grid = QGridLayout()
layout.addLayout(grid)
for row in range(3):
for column in range(3):
grid.addWidget(LCDRange(), row, column)
if __name__ == '__main__':
app = QApplication(sys.argv)
widget = MyWidget()
widget.show()
sys.exit(app.exec())
# PySide6 tutorial 9
import sys
from PySide6.QtCore import QRect, Qt, Signal, Slot
from PySide6.QtGui import QColor, QFont, QPainter, QPalette
from PySide6.QtWidgets import (QApplication, QGridLayout, QLCDNumber,
QPushButton, QSlider, QVBoxLayout, QWidget)
class LCDRange(QWidget):
value_changed = Signal(int)
def __init__(self, parent=None):
super().__init__(parent)
lcd = QLCDNumber(2)
self.slider = QSlider(Qt.Horizontal)
self.slider.setRange(0, 99)
self.slider.setValue(0)
self.slider.valueChanged.connect(lcd.display)
self.slider.valueChanged.connect(self.value_changed)
layout = QVBoxLayout(self)
layout.addWidget(lcd)
layout.addWidget(self.slider)
self.setFocusProxy(self.slider)
def value(self):
return self.slider.value()
@Slot(int)
def set_value(self, value):
self.slider.setValue(value)
def set_range(self, minValue, maxValue):
if minValue < 0 or maxValue > 99 or minValue > maxValue:
qWarning(f"LCDRange::setRange({minValue}, {maxValue})\n"
"\tRange must be 0..99\n"
"\tand minValue must not be greater than maxValue")
return
self.slider.setRange(minValue, maxValue)
class CannonField(QWidget):
angle_changed = Signal(int)
def __init__(self, parent=None):
super().__init__(parent)
self._current_angle = 45
self.setPalette(QPalette(QColor(250, 250, 200)))
self.setAutoFillBackground(True)
def angle(self):
return self._current_angle
@Slot(int)
def set_angle(self, angle):
if angle < 5:
angle = 5
if angle > 70:
angle = 70
if self._current_angle == angle:
return
self._current_angle = angle
self.update()
self.angle_changed.emit(self._current_angle)
def paintEvent(self, event):
painter = QPainter(self)
painter.setPen(Qt.NoPen)
painter.setBrush(Qt.blue)
painter.translate(0, self.rect().height())
painter.drawPie(QRect(-35, -35, 70, 70), 0, 90 * 16)
painter.rotate(-self._current_angle)
painter.drawRect(QRect(33, -4, 15, 8))
# QPainter needs an explicit end() in PyPy. This will become a context manager in 6.3.
painter.end()
class MyWidget(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
quit = QPushButton("Quit")
quit.setFont(QFont("Times", 18, QFont.Bold))
quit.clicked.connect(qApp.quit)
angle = LCDRange()
angle.set_range(5, 70)
cannon_field = CannonField()
angle.value_changed.connect(cannon_field.set_angle)
cannon_field.angle_changed.connect(angle.set_value)
grid_layout = QGridLayout(self)
grid_layout.addWidget(quit, 0, 0)
grid_layout.addWidget(angle, 1, 0)
grid_layout.addWidget(cannon_field, 1, 1, 2, 1)
grid_layout.setColumnStretch(1, 10)
angle.set_value(60)
angle.setFocus()
if __name__ == '__main__':
app = QApplication(sys.argv)
widget = MyWidget()
widget.setGeometry(100, 100, 500, 355)
widget.show()
sys.exit(app.exec())
# PySide6 tutorial 8
import sys
from PySide6.QtCore import Signal, Slot, Qt
from PySide6.QtGui import QColor, QFont, QPainter, QPalette
from PySide6.QtWidgets import (QApplication, QGridLayout, QLCDNumber,
QPushButton, QSlider, QVBoxLayout, QWidget)
class LCDRange(QWidget):
value_changed = Signal(int)
def __init__(self, parent=None):
super().__init__(parent)
lcd = QLCDNumber(2)
self.slider = QSlider(Qt.Horizontal)
self.slider.setRange(0, 99)
self.slider.setValue(0)
self.slider.valueChanged.connect(lcd.display)
self.slider.valueChanged.connect(self.value_changed)
layout = QVBoxLayout(self)
layout.addWidget(lcd)
layout.addWidget(self.slider)
self.setFocusProxy(self.slider)
def value(self):
return self.slider.value()
@Slot(int)
def set_value(self, value):
self.slider.setValue(value)
def set_range(self, minValue, maxValue):
if minValue < 0 or maxValue > 99 or minValue > maxValue:
qWarning("LCDRange.setRange({minValue}, {maxValue})\n"
"\tRange must be 0..99\n"
"\tand minValue must not be greater than maxValue")
return
self.slider.setRange(minValue, maxValue)
class CannonField(QWidget):
angle_changed = Signal(int)
def __init__(self, parent=None):
super().__init__(parent)
self._current_angle = 45
self.setPalette(QPalette(QColor(250, 250, 200)))
self.setAutoFillBackground(True)
def angle(self):
return self._current_angle
@Slot(int)
def set_angle(self, angle):
if angle < 5:
angle = 5
if angle > 70:
angle = 70
if self._current_angle == angle:
return
self._current_angle = angle
self.update()
self.angle_changed.emit(self._current_angle)
def paintEvent(self, event):
painter = QPainter(self)
painter.drawText(200, 200, f"Angle = {self._current_angle}")
# QPainter needs an explicit end() in PyPy. This will become a context manager in 6.3.
painter.end()
class MyWidget(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
quit = QPushButton("Quit")
quit.setFont(QFont("Times", 18, QFont.Bold))
quit.clicked.connect(qApp.quit)
angle = LCDRange()
angle.set_range(5, 70)
cannon_field = CannonField()
angle.value_changed.connect(cannon_field.set_angle)
cannon_field.angle_changed.connect(angle.set_value)
grid_layout = QGridLayout(self)
grid_layout.addWidget(quit, 0, 0)
grid_layout.addWidget(angle, 1, 0)
grid_layout.addWidget(cannon_field, 1, 1, 2, 1)
grid_layout.setColumnStretch(1, 10)
angle.set_value(60)
angle.setFocus()
if __name__ == '__main__':
app = QApplication(sys.argv)
widget = MyWidget()
widget.setGeometry(100, 100, 500, 355)
widget.show()
sys.exit(app.exec())
# PySide6 tutorial 13
import sys
import math
import random
from PySide6.QtCore import (QPoint, QRect, QTime, QTimer, Qt, SIGNAL, SLOT,
Signal, Slot)
from PySide6.QtGui import QColor, QFont, QPainter, QPalette, QRegion
from PySide6.QtWidgets import (QApplication, QGridLayout, QHBoxLayout, QLabel,
QLCDNumber, QPushButton, QSizePolicy, QSlider,
QVBoxLayout, QWidget)
class LCDRange(QWidget):
value_changed = Signal(int)
def __init__(self, text=None, parent=None):
if isinstance(text, QWidget):
parent = text
text = None
super().__init__(parent)
self.init()
if text:
self.set_text(text)
def init(self):
lcd = QLCDNumber(2)
self.slider = QSlider(Qt.Horizontal)
self.slider.setRange(0, 99)
self.slider.setValue(0)
self.label = QLabel()
self.label.setAlignment(Qt.AlignHCenter | Qt.AlignTop)
self.label.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed)
self.slider.valueChanged.connect(lcd.display)
self.slider.valueChanged.connect(self.value_changed)
layout = QVBoxLayout(self)
layout.addWidget(lcd)
layout.addWidget(self.slider)
layout.addWidget(self.label)
self.setFocusProxy(self.slider)
def value(self):
return self.slider.value()
@Slot(int)
def set_value(self, value):
self.slider.setValue(value)
def text(self):
return self.label.text()
def set_range(self, minValue, maxValue):
if minValue < 0 or maxValue > 99 or minValue > maxValue:
qWarning(f"LCDRange::setRange({minValue}, {maxValue})\n"
"\tRange must be 0..99\n"
"\tand minValue must not be greater than maxValue")
return
self.slider.setRange(minValue, maxValue)
def set_text(self, text):
self.label.setText(text)
class CannonField(QWidget):
angle_changed = Signal(int)
force_changed = Signal(int)
hit = Signal()
missed = Signal()
can_shoot = Signal(bool)
def __init__(self, parent=None):
super().__init__(parent)
self._current_angle = 45
self._current_force = 0
self._timer_count = 0
self._auto_shoot_timer = QTimer(self)
self._auto_shoot_timer.timeout.connect(self.move_shot)
self._shoot_angle = 0
self._shoot_force = 0
self.target = QPoint(0, 0)
self._game_ended = False
self.setPalette(QPalette(QColor(250, 250, 200)))
self.setAutoFillBackground(True)
self.new_target()
def angle(self):
return self._current_angle
@Slot(int)
def set_angle(self, angle):
if angle < 5:
angle = 5
if angle > 70:
angle = 70
if self._current_angle == angle:
return
self._current_angle = angle
self.update()
self.angle_changed.emit(self._current_angle)
def force(self):
return self._current_force
@Slot(int)
def set_force(self, force):
if force < 0:
force = 0
if self._current_force == force:
return
self._current_force = force
self.force_changed.emit(self._current_force)
@Slot()
def shoot(self):
if self.is_shooting():
return
self._timer_count = 0
self._shoot_angle = self._current_angle
self._shoot_force = self._current_force
self._auto_shoot_timer.start(5)
self.can_shoot.emit(False)
first_time = True
def new_target(self):
if CannonField.first_time:
CannonField.first_time = False
midnight = QTime(0, 0, 0)
random.seed(midnight.secsTo(QTime.currentTime()))
self.target = QPoint(200 + random.randint(0, 190 - 1), 10 + random.randint(0, 255 - 1))
self.update()
def set_game_over(self):
if self._game_ended:
return
if self.is_shooting():
self._auto_shoot_timer.stop()
self._game_ended = True
self.update()
def restart_game(self):
if self.is_shooting():
self._auto_shoot_timer.stop()
self._game_ended = False
self.update()
self.can_shoot.emit(True)
@Slot()
def move_shot(self):
region = QRegion(self.shot_rect())
self._timer_count += 1
shot_r = self.shot_rect()
if shot_r.intersects(self.target_rect()):
self._auto_shoot_timer.stop()
self.hit.emit()
self.can_shoot.emit(True)
elif shot_r.x() > self.width() or shot_r.y() > self.height():
self._auto_shoot_timer.stop()
self.missed.emit()
self.can_shoot.emit(True)
else:
region = region.united(QRegion(shot_r))
self.update(region)
def paintEvent(self, event):
painter = QPainter(self)
if self._game_ended:
painter.setPen(Qt.black)
painter.setFont(QFont("Courier", 48, QFont.Bold))
painter.drawText(self.rect(), Qt.AlignCenter, "Game Over")
self.paint_cannon(painter)
if self.is_shooting():
self.paint_shot(painter)
if not self._game_ended:
self.paint_target(painter)
# QPainter needs an explicit end() in PyPy. This will become a context manager in 6.3.
painter.end()
def paint_shot(self, painter):
painter.setPen(Qt.NoPen)
painter.setBrush(Qt.black)
painter.drawRect(self.shot_rect())
def paint_target(self, painter):
painter.setPen(Qt.black)
painter.setBrush(Qt.red)
painter.drawRect(self.target_rect())
barrel_rect = QRect(33, -4, 15, 8)
def paint_cannon(self, painter):
painter.setPen(Qt.NoPen)
painter.setBrush(Qt.blue)
painter.save()
painter.translate(0, self.height())
painter.drawPie(QRect(-35, -35, 70, 70), 0, 90 * 16)
painter.rotate(-self._current_angle)
painter.drawRect(CannonField.barrel_rect)
painter.restore()
def cannon_rect(self):
result = QRect(0, 0, 50, 50)
result.moveBottomLeft(self.rect().bottomLect())
return result
def shot_rect(self):
gravity = 4.0
time = self._timer_count / 40.0
velocity = self._shoot_force
radians = self._shoot_angle * math.pi / 180
velx = velocity * math.cos(radians)
vely = velocity * math.sin(radians)
x0 = (CannonField.barrel_rect.right() + 5) * math.cos(radians)
y0 = (CannonField.barrel_rect.right() + 5) * math.sin(radians)
x = x0 + velx * time
y = y0 + vely * time - 0.5 * gravity * time * time
result = QRect(0, 0, 6, 6)
result.moveCenter(QPoint(round(x), self.height() - 1 - round(y)))
return result
def target_rect(self):
result = QRect(0, 0, 20, 10)
result.moveCenter(QPoint(self.target.x(), self.height() - 1 - self.target.y()))
return result
def game_over(self):
return self._game_ended
def is_shooting(self):
return self._auto_shoot_timer.isActive()
class GameBoard(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
quit = QPushButton("&Quit")
quit.setFont(QFont("Times", 18, QFont.Bold))
quit.clicked.connect(qApp.quit)
angle = LCDRange("ANGLE")
angle.set_range(5, 70)
force = LCDRange("FORCE")
force.set_range(10, 50)
self._cannon_field = CannonField()
angle.value_changed.connect(self._cannon_field.set_angle)
self._cannon_field.angle_changed.connect(angle.set_value)
force.value_changed.connect(self._cannon_field.set_force)
self._cannon_field.force_changed.connect(force.set_value)
self._cannon_field.hit.connect(self.hit)
self._cannon_field.missed.connect(self.missed)
shoot = QPushButton("&Shoot")
shoot.setFont(QFont("Times", 18, QFont.Bold))
shoot.clicked.connect(self.fire)
self._cannon_field.can_shoot.connect(shoot.setEnabled)
restart = QPushButton("&New Game")
restart.setFont(QFont("Times", 18, QFont.Bold))
restart.clicked.connect(self.new_game)
self.hits = QLCDNumber(2)
self._shots_left = QLCDNumber(2)
hits_label = QLabel("HITS")
shots_left_label = QLabel("SHOTS LEFT")
top_layout = QHBoxLayout()
top_layout.addWidget(shoot)
top_layout.addWidget(self.hits)
top_layout.addWidget(hits_label)
top_layout.addWidget(self._shots_left)
top_layout.addWidget(shots_left_label)
top_layout.addStretch(1)
top_layout.addWidget(restart)
left_layout = QVBoxLayout()
left_layout.addWidget(angle)
left_layout.addWidget(force)
grid_layout = QGridLayout(self)
grid_layout.addWidget(quit, 0, 0)
grid_layout.addLayout(top_layout, 0, 1)
grid_layout.addLayout(left_layout, 1, 0)
grid_layout.addWidget(self._cannon_field, 1, 1, 2, 1)
grid_layout.setColumnStretch(1, 10)
angle.set_value(60)
force.set_value(25)
angle.setFocus()
self.new_game()
@Slot()
def fire(self):
if self._cannon_field.game_over() or self._cannon_field.is_shooting():
return
self._shots_left.display(self._shots_left.intValue() - 1)
self._cannon_field.shoot()
@Slot()
def hit(self):
self.hits.display(self.hits.intValue() + 1)
if self._shots_left.intValue() == 0:
self._cannon_field.set_game_over()
else:
self._cannon_field.new_target()
@Slot()
def missed(self):
if self._shots_left.intValue() == 0:
self._cannon_field.set_game_over()
@Slot()
def new_game(self):
self._shots_left.display(15)
self.hits.display(0)
self._cannon_field.restart_game()
self._cannon_field.new_target()
if __name__ == '__main__':
app = QApplication(sys.argv)
board = GameBoard()
board.setGeometry(100, 100, 500, 355)
board.show()
sys.exit(app.exec())
# PySide6 tutorial 10
import sys
from PySide6.QtCore import QRect, Qt, Signal, Slot
from PySide6.QtGui import QColor, QFont, QPainter, QPalette
from PySide6.QtWidgets import (QApplication, QGridLayout, QLCDNumber,
QPushButton, QSlider, QVBoxLayout, QWidget)
class LCDRange(QWidget):
value_changed = Signal(int)
def __init__(self, parent=None):
super().__init__(parent)
lcd = QLCDNumber(2)
self.slider = QSlider(Qt.Horizontal)
self.slider.setRange(0, 99)
self.slider.setValue(0)
self.slider.valueChanged.connect(lcd.display)
self.slider.valueChanged.connect(self.value_changed)
layout = QVBoxLayout(self)
layout.addWidget(lcd)
layout.addWidget(self.slider)
self.setFocusProxy(self.slider)
def value(self):
return self.slider.value()
@Slot(int)
def set_value(self, value):
self.slider.setValue(value)
def set_range(self, minValue, maxValue):
if minValue < 0 or maxValue > 99 or minValue > maxValue:
qWarning(f"LCDRange::setRange({minValue}, {maxValue})\n"
"\tRange must be 0..99\n"
"\tand minValue must not be greater than maxValue")
return
self.slider.setRange(minValue, maxValue)
class CannonField(QWidget):
angle_changed = Signal(int)
force_changed = Signal(int)
def __init__(self, parent=None):
super().__init__(parent)
self._current_angle = 45
self._current_force = 0
self.setPalette(QPalette(QColor(250, 250, 200)))
self.setAutoFillBackground(True)
def angle(self):
return self._current_angle
@Slot(int)
def set_angle(self, angle):
if angle < 5:
angle = 5
if angle > 70:
angle = 70
if self._current_angle == angle:
return
self._current_angle = angle
self.update()
self.angle_changed.emit(self._current_angle)
def force(self):
return self._current_force
@Slot(int)
def set_force(self, force):
if force < 0:
force = 0
if self._current_force == force:
return
self._current_force = force
self.force_changed.emit(self._current_force)
def paintEvent(self, event):
painter = QPainter(self)
painter.setPen(Qt.NoPen)
painter.setBrush(Qt.blue)
painter.translate(0, self.height())
painter.drawPie(QRect(-35, -35, 70, 70), 0, 90 * 16)
painter.rotate(-self._current_angle)
painter.drawRect(QRect(33, -4, 15, 8))
# QPainter needs an explicit end() in PyPy. This will become a context manager in 6.3.
painter.end()
def cannon_rect(self):
result = QRect(0, 0, 50, 50)
result.moveBottomLeft(self.rect().bottomLect())
return result
class MyWidget(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
quit = QPushButton("&Quit")
quit.setFont(QFont("Times", 18, QFont.Bold))
quit.clicked.connect(qApp.quit)
angle = LCDRange()
angle.set_range(5, 70)
force = LCDRange()
force.set_range(10, 50)
cannon_field = CannonField()
angle.value_changed.connect(cannon_field.set_angle)
cannon_field.angle_changed.connect(angle.set_value)
force.value_changed.connect(cannon_field.set_force)
cannon_field.force_changed.connect(force.set_value)
left_layout = QVBoxLayout()
left_layout.addWidget(angle)
left_layout.addWidget(force)
grid_layout = QGridLayout(self)
grid_layout.addWidget(quit, 0, 0)
grid_layout.addLayout(left_layout, 1, 0)
grid_layout.addWidget(cannon_field, 1, 1, 2, 1)
grid_layout.setColumnStretch(1, 10)
angle.set_value(60)
force.set_value(25)
angle.setFocus()
if __name__ == '__main__':
app = QApplication(sys.argv)
widget = MyWidget()
widget.setGeometry(100, 100, 500, 355)
widget.show()
sys.exit(app.exec())
# PySide6 tutorial 7
import sys
from PySide6.QtCore import Signal, Slot, Qt
from PySide6.QtGui import QFont
from PySide6.QtWidgets import (QApplication, QGridLayout, QLCDNumber,
QPushButton, QSlider, QVBoxLayout, QWidget)
class LCDRange(QWidget):
value_changed = Signal(int)
def __init__(self, parent=None):
super().__init__(parent)
lcd = QLCDNumber(2)
self.slider = QSlider(Qt.Horizontal)
self.slider.setRange(0, 99)
self.slider.setValue(0)
self.slider.valueChanged.connect(lcd.display)
self.slider.valueChanged.connect(self.value_changed)
layout = QVBoxLayout(self)
layout.addWidget(lcd)
layout.addWidget(self.slider)
def value(self):
return self.slider.value()
@Slot(int)
def set_value(self, value):
self.slider.setValue(value)
class MyWidget(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
quit = QPushButton("Quit")
quit.setFont(QFont("Times", 18, QFont.Bold))
quit.clicked.connect(qApp.quit)
previous_range = None
layout = QVBoxLayout(self)
layout.addWidget(quit)
grid = QGridLayout()
layout.addLayout(grid)
for row in range(3):
for column in range(3):
lcd_range = LCDRange()
grid.addWidget(lcd_range, row, column)
if previous_range:
lcd_range.value_changed.connect(previous_range.set_value)
previous_range = lcd_range
if __name__ == '__main__':
app = QApplication(sys.argv)
widget = MyWidget()
widget.show()
sys.exit(app.exec())
# PySide6 tutorial 3
import sys
from PySide6.QtGui import QFont
from PySide6.QtWidgets import (QApplication, QPushButton, QWidget)
if __name__ == '__main__':
app = QApplication(sys.argv)
window = QWidget()
window.resize(200, 120)
quit = QPushButton("Quit", window)
quit.setFont(QFont("Times", 18, QFont.Bold))
quit.setGeometry(10, 40, 180, 40)
quit.clicked.connect(app.quit)
window.show()
sys.exit(app.exec())
# PySide6 tutorial 4
import sys
from PySide6.QtGui import QFont
from PySide6.QtWidgets import (QApplication, QPushButton, QWidget)
class MyWidget(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.setFixedSize(200, 120)
self.quit = QPushButton("Quit", self)
self.quit.setGeometry(62, 40, 75, 30)
self.quit.setFont(QFont("Times", 18, QFont.Bold))
self.quit.clicked.connect(qApp.quit)
if __name__ == '__main__':
app = QApplication(sys.argv)
widget = MyWidget()
widget.show()
sys.exit(app.exec())
# PySide6 tutorial 1
import sys
from PySide6.QtWidgets import QApplication, QPushButton
if __name__ == '__main__':
app = QApplication(sys.argv)
hello = QPushButton("Hello world!")
hello.resize(100, 30)
hello.show()
sys.exit(app.exec())
# PySide6 tutorial 12
import sys
import math
import random
from PySide6.QtCore import QPoint, QRect, QTime, QTimer, Qt, Signal, Slot
from PySide6.QtGui import QColor, QFont, QPainter, QPalette, QRegion
from PySide6.QtWidgets import (QApplication, QGridLayout, QHBoxLayout,
QLabel, QLCDNumber, QPushButton, QSlider,
QVBoxLayout, QWidget)
class LCDRange(QWidget):
value_changed = Signal(int)
def __init__(self, text=None, parent=None):
if isinstance(text, QWidget):
parent = text
text = None
super().__init__(parent)
self.init()
if text:
self.set_text(text)
def init(self):
lcd = QLCDNumber(2)
self.slider = QSlider(Qt.Horizontal)
self.slider.setRange(0, 99)
self.slider.setValue(0)
self.label = QLabel()
self.label.setAlignment(Qt.AlignHCenter | Qt.AlignTop)
self.slider.valueChanged.connect(lcd.display)
self.slider.valueChanged.connect(self.value_changed)
layout = QVBoxLayout(self)
layout.addWidget(lcd)
layout.addWidget(self.slider)
layout.addWidget(self.label)
self.setFocusProxy(self.slider)
def value(self):
return self.slider.value()
@Slot(int)
def set_value(self, value):
self.slider.setValue(value)
def text(self):
return self.label.text()
def set_range(self, minValue, maxValue):
if minValue < 0 or maxValue > 99 or minValue > maxValue:
qWarning(f"LCDRange::setRange({minValue}, {maxValue})\n"
"\tRange must be 0..99\n"
"\tand minValue must not be greater than maxValue")
return
self.slider.setRange(minValue, maxValue)
def set_text(self, text):
self.label.setText(text)
class CannonField(QWidget):
angle_changed = Signal(int)
force_changed = Signal(int)
hit = Signal()
missed = Signal()
def __init__(self, parent=None):
super().__init__(parent)
self._current_angle = 45
self._current_force = 0
self._timer_count = 0
self._auto_shoot_timer = QTimer(self)
self._auto_shoot_timer.timeout.connect(self.move_shot)
self._shoot_angle = 0
self._shoot_force = 0
self.target = QPoint(0, 0)
self.setPalette(QPalette(QColor(250, 250, 200)))
self.setAutoFillBackground(True)
self.new_target()
def angle(self):
return self._current_angle
@Slot(int)
def set_angle(self, angle):
if angle < 5:
angle = 5
if angle > 70:
angle = 70
if self._current_angle == angle:
return
self._current_angle = angle
self.update()
self.angle_changed.emit(self._current_angle)
def force(self):
return self._current_force
@Slot(int)
def set_force(self, force):
if force < 0:
force = 0
if self._current_force == force:
return
self._current_force = force
self.force_changed.emit(self._current_force)
@Slot()
def shoot(self):
if self._auto_shoot_timer.isActive():
return
self._timer_count = 0
self._shoot_angle = self._current_angle
self._shoot_force = self._current_force
self._auto_shoot_timer.start(5)
first_time = True
def new_target(self):
if CannonField.first_time:
CannonField.first_time = False
midnight = QTime(0, 0, 0)
random.seed(midnight.secsTo(QTime.currentTime()))
self.target = QPoint(200 + random.randint(0, 190 - 1), 10 + random.randint(0, 255 - 1))
self.update()
@Slot()
def move_shot(self):
region = QRegion(self.shot_rect())
self._timer_count += 1
shot_r = self.shot_rect()
if shot_r.intersects(self.target_rect()):
self._auto_shoot_timer.stop()
self.hit.emit()
elif shot_r.x() > self.width() or shot_r.y() > self.height():
self._auto_shoot_timer.stop()
self.missed.emit()
else:
region = region.united(QRegion(shot_r))
self.update(region)
def paintEvent(self, event):
painter = QPainter(self)
self.paint_cannon(painter)
if self._auto_shoot_timer.isActive():
self.paint_shot(painter)
self.paint_target(painter)
# QPainter needs an explicit end() in PyPy. This will become a context manager in 6.3.
painter.end()
def paint_shot(self, painter):
painter.setPen(Qt.NoPen)
painter.setBrush(Qt.black)
painter.drawRect(self.shot_rect())
def paint_target(self, painter):
painter.setPen(Qt.black)
painter.setBrush(Qt.red)
painter.drawRect(self.target_rect())
barrel_rect = QRect(33, -4, 15, 8)
def paint_cannon(self, painter):
painter.setPen(Qt.NoPen)
painter.setBrush(Qt.blue)
painter.save()
painter.translate(0, self.height())
painter.drawPie(QRect(-35, -35, 70, 70), 0, 90 * 16)
painter.rotate(-self._current_angle)
painter.drawRect(CannonField.barrel_rect)
painter.restore()
def cannon_rect(self):
result = QRect(0, 0, 50, 50)
result.moveBottomLeft(self.rect().bottomLect())
return result
def shot_rect(self):
gravity = 4.0
time = self._timer_count / 40.0
velocity = self._shoot_force
radians = self._shoot_angle * math.pi / 180
velx = velocity * math.cos(radians)
vely = velocity * math.sin(radians)
x0 = (CannonField.barrel_rect.right() + 5) * math.cos(radians)
y0 = (CannonField.barrel_rect.right() + 5) * math.sin(radians)
x = x0 + velx * time
y = y0 + vely * time - 0.5 * gravity * time * time
result = QRect(0, 0, 6, 6)
result.moveCenter(QPoint(round(x), self.height() - 1 - round(y)))
return result
def target_rect(self):
result = QRect(0, 0, 20, 10)
result.moveCenter(QPoint(self.target.x(), self.height() - 1 - self.target.y()))
return result
class MyWidget(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
quit = QPushButton("&Quit")
quit.setFont(QFont("Times", 18, QFont.Bold))
quit.clicked.connect(qApp.quit)
angle = LCDRange("ANGLE")
angle.set_range(5, 70)
force = LCDRange("FORCE")
force.set_range(10, 50)
cannon_field = CannonField()
angle.value_changed.connect(cannon_field.set_angle)
cannon_field.angle_changed.connect(angle.set_value)
force.value_changed.connect(cannon_field.set_force)
cannon_field.force_changed.connect(force.set_value)
shoot = QPushButton("&Shoot")
shoot.setFont(QFont("Times", 18, QFont.Bold))
shoot.clicked.connect(cannon_field.shoot)
top_layout = QHBoxLayout()
top_layout.addWidget(shoot)
top_layout.addStretch(1)
left_layout = QVBoxLayout()
left_layout.addWidget(angle)
left_layout.addWidget(force)
grid_layout = QGridLayout(self)
grid_layout.addWidget(quit, 0, 0)
grid_layout.addLayout(top_layout, 0, 1)
grid_layout.addLayout(left_layout, 1, 0)
grid_layout.addWidget(cannon_field, 1, 1, 2, 1)
grid_layout.setColumnStretch(1, 10)
angle.set_value(60)
force.set_value(25)
angle.setFocus()
if __name__ == '__main__':
app = QApplication(sys.argv)
widget = MyWidget()
widget.setGeometry(100, 100, 500, 355)
widget.show()
sys.exit(app.exec())
# PySide6 tutorial 2
import sys
from PySide6.QtCore import (QPoint, QRect, QTime, QTimer, Qt)
from PySide6.QtGui import QFont
from PySide6.QtWidgets import (QApplication, QPushButton)
if __name__ == '__main__':
app = QApplication(sys.argv)
quit = QPushButton("Quit")
quit.resize(75, 30)
quit.setFont(QFont("Times", 18, QFont.Bold))
quit.clicked.connect(app.quit)
quit.show()
sys.exit(app.exec())
# PySide6 tutorial 5
import sys
from PySide6.QtCore import Qt
from PySide6.QtGui import QFont
from PySide6.QtWidgets import (QApplication, QLCDNumber, QPushButton,
QSlider, QVBoxLayout, QWidget)
class MyWidget(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
quit = QPushButton("Quit")
quit.setFont(QFont("Times", 18, QFont.Bold))
lcd = QLCDNumber(2)
slider = QSlider(Qt.Horizontal)
slider.setRange(0, 99)
slider.setValue(0)
quit.clicked.connect(qApp.quit)
slider.valueChanged.connect(lcd.display)
layout = QVBoxLayout(self)
layout.addWidget(quit)
layout.addWidget(lcd)
layout.addWidget(slider)
if __name__ == '__main__':
app = QApplication(sys.argv)
widget = MyWidget()
widget.show()
sys.exit(app.exec())
# PySide6 tutorial 11
import sys
import math
from PySide6.QtCore import QPoint, QRect, QTimer, Qt, Signal, Slot
from PySide6.QtGui import QColor, QFont, QPainter, QPalette, QRegion
from PySide6.QtWidgets import (QApplication, QGridLayout, QHBoxLayout,
QLCDNumber, QPushButton, QSlider,
QVBoxLayout, QWidget)
class LCDRange(QWidget):
value_changed = Signal(int)
def __init__(self, parent=None):
super().__init__(parent)
lcd = QLCDNumber(2)
self.slider = QSlider(Qt.Horizontal)
self.slider.setRange(0, 99)
self.slider.setValue(0)
self.slider.valueChanged.connect(lcd.display)
self.slider.valueChanged.connect(self.value_changed)
layout = QVBoxLayout(self)
layout.addWidget(lcd)
layout.addWidget(self.slider)
self.setFocusProxy(self.slider)
def value(self):
return self.slider.value()
@Slot(int)
def set_value(self, value):
self.slider.setValue(value)
def set_range(self, minValue, maxValue):
if minValue < 0 or maxValue > 99 or minValue > maxValue:
qWarning(f"LCDRange::setRange({minValue}, {maxValue})\n"
"\tRange must be 0..99\n"
"\tand minValue must not be greater than maxValue")
return
self.slider.setRange(minValue, maxValue)
class CannonField(QWidget):
angle_changed = Signal(int)
force_changed = Signal(int)
def __init__(self, parent=None):
super().__init__(parent)
self._current_angle = 45
self._current_force = 0
self._timer_count = 0
self._auto_shoot_timer = QTimer(self)
self._auto_shoot_timer.timeout.connect(self.move_shot)
self._shoot_angle = 0
self._shoot_force = 0
self.setPalette(QPalette(QColor(250, 250, 200)))
self.setAutoFillBackground(True)
def angle(self):
return self._current_angle
@Slot(int)
def set_angle(self, angle):
if angle < 5:
angle = 5
if angle > 70:
angle = 70
if self._current_angle == angle:
return
self._current_angle = angle
self.update()
self.angle_changed.emit(self._current_angle)
def force(self):
return self._current_force
@Slot(int)
def set_force(self, force):
if force < 0:
force = 0
if self._current_force == force:
return
self._current_force = force
self.force_changed.emit(self._current_force)
@Slot()
def shoot(self):
if self._auto_shoot_timer.isActive():
return
self._timer_count = 0
self._shoot_angle = self._current_angle
self._shoot_force = self._current_force
self._auto_shoot_timer.start(5)
@Slot()
def move_shot(self):
region = QRegion(self.shot_rect())
self._timer_count += 1
shot_r = self.shot_rect()
if shot_r.x() > self.width() or shot_r.y() > self.height():
self._auto_shoot_timer.stop()
else:
region = region.united(QRegion(shot_r))
self.update(region)
def paintEvent(self, event):
painter = QPainter(self)
self.paint_cannon(painter)
if self._auto_shoot_timer.isActive():
self.paint_shot(painter)
# QPainter needs an explicit end() in PyPy. This will become a context manager in 6.3.
painter.end()
def paint_shot(self, painter):
painter.setPen(Qt.NoPen)
painter.setBrush(Qt.black)
painter.drawRect(self.shot_rect())
barrel_rect = QRect(33, -4, 15, 8)
def paint_cannon(self, painter):
painter.setPen(Qt.NoPen)
painter.setBrush(Qt.blue)
painter.save()
painter.translate(0, self.height())
painter.drawPie(QRect(-35, -35, 70, 70), 0, 90 * 16)
painter.rotate(-self._current_angle)
painter.drawRect(CannonField.barrel_rect)
painter.restore()
def cannon_rect(self):
result = QRect(0, 0, 50, 50)
result.moveBottomLeft(self.rect().bottomLect())
return result
def shot_rect(self):
gravity = 4.0
time = self._timer_count / 40.0
velocity = self._shoot_force
radians = self._shoot_angle * math.pi / 180
velx = velocity * math.cos(radians)
vely = velocity * math.sin(radians)
x0 = (CannonField.barrel_rect.right() + 5) * math.cos(radians)
y0 = (CannonField.barrel_rect.right() + 5) * math.sin(radians)
x = x0 + velx * time
y = y0 + vely * time - 0.5 * gravity * time * time
result = QRect(0, 0, 6, 6)
result.moveCenter(QPoint(round(x), self.height() - 1 - round(y)))
return result
class MyWidget(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
quit = QPushButton("&Quit")
quit.setFont(QFont("Times", 18, QFont.Bold))
quit.clicked.connect(qApp.quit)
angle = LCDRange()
angle.set_range(5, 70)
force = LCDRange()
force.set_range(10, 50)
cannon_field = CannonField()
angle.value_changed.connect(cannon_field.set_angle)
cannon_field.angle_changed.connect(angle.set_value)
force.value_changed.connect(cannon_field.set_force)
cannon_field.force_changed.connect(force.set_value)
shoot = QPushButton("&Shoot")
shoot.setFont(QFont("Times", 18, QFont.Bold))
shoot.clicked.connect(cannon_field.shoot)
top_layout = QHBoxLayout()
top_layout.addWidget(shoot)
top_layout.addStretch(1)
left_layout = QVBoxLayout()
left_layout.addWidget(angle)
left_layout.addWidget(force)
grid_layout = QGridLayout(self)
grid_layout.addWidget(quit, 0, 0)
grid_layout.addLayout(top_layout, 0, 1)
grid_layout.addLayout(left_layout, 1, 0)
grid_layout.addWidget(cannon_field, 1, 1, 2, 1)
grid_layout.setColumnStretch(1, 10)
angle.set_value(60)
force.set_value(25)
angle.setFocus()
if __name__ == '__main__':
app = QApplication(sys.argv)
widget = MyWidget()
widget.setGeometry(100, 100, 500, 355)
widget.show()
sys.exit(app.exec())
# PySide6 tutorial 14
import sys
import math
import random
from PySide6.QtCore import (QPoint, QRect, QTime, QTimer, QSize, Qt, SIGNAL,
SLOT, Signal, Slot)
from PySide6.QtGui import (QColor, QFont, QKeySequence, QPainter, QPalette,
QShortcut, QRegion)
from PySide6.QtWidgets import (QApplication, QFrame, QGridLayout, QHBoxLayout,
QLabel, QLCDNumber, QPushButton, QSizePolicy,
QSlider, QVBoxLayout, QWidget)
class LCDRange(QWidget):
value_changed = Signal(int)
def __init__(self, text=None, parent=None):
if isinstance(text, QWidget):
parent = text
text = None
super().__init__(parent)
self.init()
if text:
self.set_text(text)
def init(self):
lcd = QLCDNumber(2)
self.slider = QSlider(Qt.Horizontal)
self.slider.setRange(0, 99)
self.slider.setValue(0)
self.label = QLabel()
self.label.setAlignment(Qt.AlignHCenter | Qt.AlignTop)
self.label.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed)
self.slider.valueChanged.connect(lcd.display)
self.slider.valueChanged.connect(self.value_changed)
layout = QVBoxLayout(self)
layout.addWidget(lcd)
layout.addWidget(self.slider)
layout.addWidget(self.label)
self.setFocusProxy(self.slider)
def value(self):
return self.slider.value()
@Slot(int)
def set_value(self, value):
self.slider.setValue(value)
def text(self):
return self.label.text()
def set_range(self, minValue, maxValue):
if minValue < 0 or maxValue > 99 or minValue > maxValue:
qWarning(f"LCDRange::setRange({minValue}, {maxValue})\n"
"\tRange must be 0..99\n"
"\tand minValue must not be greater than maxValue")
return
self.slider.setRange(minValue, maxValue)
def set_text(self, text):
self.label.setText(text)
class CannonField(QWidget):
angle_changed = Signal(int)
force_changed = Signal(int)
hit = Signal()
missed = Signal()
can_shoot = Signal(bool)
def __init__(self, parent=None):
super().__init__(parent)
self._current_angle = 45
self._current_force = 0
self._timer_count = 0
self._auto_shoot_timer = QTimer(self)
self._auto_shoot_timer.timeout.connect(self.move_shot)
self._shoot_angle = 0
self._shoot_force = 0
self.target = QPoint(0, 0)
self._game_ended = False
self._barrel_pressed = False
self.setPalette(QPalette(QColor(250, 250, 200)))
self.setAutoFillBackground(True)
self.new_target()
def angle(self):
return self._current_angle
@Slot(int)
def set_angle(self, angle):
if angle < 5:
angle = 5
if angle > 70:
angle = 70
if self._current_angle == angle:
return
self._current_angle = angle
self.update()
self.angle_changed.emit(self._current_angle)
def force(self):
return self._current_force
@Slot(int)
def set_force(self, force):
if force < 0:
force = 0
if self._current_force == force:
return
self._current_force = force
self.force_changed.emit(self._current_force)
@Slot()
def shoot(self):
if self.is_shooting():
return
self._timer_count = 0
self._shoot_angle = self._current_angle
self._shoot_force = self._current_force
self._auto_shoot_timer.start(5)
self.can_shoot.emit(False)
first_time = True
def new_target(self):
if CannonField.first_time:
CannonField.first_time = False
midnight = QTime(0, 0, 0)
random.seed(midnight.secsTo(QTime.currentTime()))
self.target = QPoint(200 + random.randint(0, 190 - 1), 10 + random.randint(0, 255 - 1))
self.update()
def set_game_over(self):
if self._game_ended:
return
if self.is_shooting():
self._auto_shoot_timer.stop()
self._game_ended = True
self.update()
def restart_game(self):
if self.is_shooting():
self._auto_shoot_timer.stop()
self._game_ended = False
self.update()
self.can_shoot.emit(True)
@Slot()
def move_shot(self):
region = QRegion(self.shot_rect())
self._timer_count += 1
shot_r = self.shot_rect()
if shot_r.intersects(self.target_rect()):
self._auto_shoot_timer.stop()
self.hit.emit()
self.can_shoot.emit(True)
elif shot_r.x() > self.width() or shot_r.y() > self.height() or shot_r.intersects(self.barrier_rect()):
self._auto_shoot_timer.stop()
self.missed.emit()
self.can_shoot.emit(True)
else:
region = region.united(QRegion(shot_r))
self.update(region)
def mousePressEvent(self, event):
if event.button() != Qt.LeftButton:
return
if self.barrel_hit(event.position().toPoint()):
self._barrel_pressed = True
def mouseMoveEvent(self, event):
if not self._barrel_pressed:
return
pos = event.position().toPoint()
if pos.x() <= 0:
pos.setX(1)
if pos.y() >= self.height():
pos.setY(self.height() - 1)
rad = math.atan((float(self.rect().bottom()) - pos.y()) / pos.x())
self.set_angle(round(rad * 180 / math.pi))
def mouseReleaseEvent(self, event):
if event.button() == Qt.LeftButton:
self._barrel_pressed = False
def paintEvent(self, event):
painter = QPainter(self)
if self._game_ended:
painter.setPen(Qt.black)
painter.setFont(QFont("Courier", 48, QFont.Bold))
painter.drawText(self.rect(), Qt.AlignCenter, "Game Over")
self.paint_cannon(painter)
self.paint_barrier(painter)
if self.is_shooting():
self.paint_shot(painter)
if not self._game_ended:
self.paint_target(painter)
# QPainter needs an explicit end() in PyPy. This will become a context manager in 6.3.
painter.end()
def paint_shot(self, painter):
painter.setPen(Qt.NoPen)
painter.setBrush(Qt.black)
painter.drawRect(self.shot_rect())
def paint_target(self, painter):
painter.setPen(Qt.black)
painter.setBrush(Qt.red)
painter.drawRect(self.target_rect())
def paint_barrier(self, painter):
painter.setPen(Qt.black)
painter.setBrush(Qt.yellow)
painter.drawRect(self.barrier_rect())
barrel_rect = QRect(33, -4, 15, 8)
def paint_cannon(self, painter):
painter.setPen(Qt.NoPen)
painter.setBrush(Qt.blue)
painter.save()
painter.translate(0, self.height())
painter.drawPie(QRect(-35, -35, 70, 70), 0, 90 * 16)
painter.rotate(-self._current_angle)
painter.drawRect(CannonField.barrel_rect)
painter.restore()
def cannon_rect(self):
result = QRect(0, 0, 50, 50)
result.moveBottomLeft(self.rect().bottomLect())
return result
def shot_rect(self):
gravity = 4.0
time = self._timer_count / 40.0
velocity = self._shoot_force
radians = self._shoot_angle * math.pi / 180
velx = velocity * math.cos(radians)
vely = velocity * math.sin(radians)
x0 = (CannonField.barrel_rect.right() + 5) * math.cos(radians)
y0 = (CannonField.barrel_rect.right() + 5) * math.sin(radians)
x = x0 + velx * time
y = y0 + vely * time - 0.5 * gravity * time * time
result = QRect(0, 0, 6, 6)
result.moveCenter(QPoint(round(x), self.height() - 1 - round(y)))
return result
def target_rect(self):
result = QRect(0, 0, 20, 10)
result.moveCenter(QPoint(self.target.x(), self.height() - 1 - self.target.y()))
return result
def barrier_rect(self):
return QRect(145, self.height() - 100, 15, 99)
def barrel_hit(self, pos):
matrix = QTransform()
matrix.translate(0, self.height())
matrix.rotate(-self._current_angle)
matrix, invertible = matrix.inverted()
return self.barrel_rect.contains(matrix.map(pos))
def game_over(self):
return self._game_ended
def is_shooting(self):
return self._auto_shoot_timer.isActive()
def sizeHint(self):
return QSize(400, 300)
class GameBoard(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
quit = QPushButton("&Quit")
quit.setFont(QFont("Times", 18, QFont.Bold))
quit.clicked.connect(qApp.quit)
angle = LCDRange("ANGLE")
angle.set_range(5, 70)
force = LCDRange("FORCE")
force.set_range(10, 50)
cannon_box = QFrame()
cannon_box.setFrameStyle(QFrame.WinPanel | QFrame.Sunken)
self._cannon_field = CannonField()
angle.value_changed.connect(self._cannon_field.set_angle)
self._cannon_field.angle_changed.connect(angle.set_value)
force.value_changed.connect(self._cannon_field.set_force)
self._cannon_field.force_changed.connect(force.set_value)
self._cannon_field.hit.connect(self.hit)
self._cannon_field.missed.connect(self.missed)
shoot = QPushButton("&Shoot")
shoot.setFont(QFont("Times", 18, QFont.Bold))
shoot.clicked.connect(self.fire)
self._cannon_field.can_shoot.connect(shoot.setEnabled)
restart = QPushButton("&New Game")
restart.setFont(QFont("Times", 18, QFont.Bold))
restart.clicked.connect(self.new_game)
self.hits = QLCDNumber(2)
self._shots_left = QLCDNumber(2)
hits_label = QLabel("HITS")
shots_left_label = QLabel("SHOTS LEFT")
QShortcut(QKeySequence(Qt.Key_Enter), self, self.fire)
QShortcut(QKeySequence(Qt.Key_Return), self, self.fire)
QShortcut(QKeySequence(Qt.CTRL + Qt.Key_Q), self, self.close)
top_layout = QHBoxLayout()
top_layout.addWidget(shoot)
top_layout.addWidget(self.hits)
top_layout.addWidget(hits_label)
top_layout.addWidget(self._shots_left)
top_layout.addWidget(shots_left_label)
top_layout.addStretch(1)
top_layout.addWidget(restart)
left_layout = QVBoxLayout()
left_layout.addWidget(angle)
left_layout.addWidget(force)
cannon_layout = QVBoxLayout()
cannon_layout.addWidget(self._cannon_field)
cannon_box.setLayout(cannon_layout)
grid_layout = QGridLayout(self)
grid_layout.addWidget(quit, 0, 0)
grid_layout.addLayout(top_layout, 0, 1)
grid_layout.addLayout(left_layout, 1, 0)
grid_layout.addWidget(cannon_box, 1, 1, 2, 1)
grid_layout.setColumnStretch(1, 10)
angle.set_value(60)
force.set_value(25)
angle.setFocus()
self.new_game()
@Slot()
def fire(self):
if self._cannon_field.game_over() or self._cannon_field.is_shooting():
return
self._shots_left.display(self._shots_left.intValue() - 1)
self._cannon_field.shoot()
@Slot()
def hit(self):
self.hits.display(self.hits.intValue() + 1)
if self._shots_left.intValue() == 0:
self._cannon_field.set_game_over()
else:
self._cannon_field.new_target()
@Slot()
def missed(self):
if self._shots_left.intValue() == 0:
self._cannon_field.set_game_over()
@Slot()
def new_game(self):
self._shots_left.display(15)
self.hits.display(0)
self._cannon_field.restart_game()
self._cannon_field.new_target()
if __name__ == '__main__':
app = QApplication(sys.argv)
board = GameBoard()
board.setGeometry(100, 100, 500, 355)
board.show()
sys.exit(app.exec())
© 2022 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.