I'm creating a Space Invaders with PyGame, and I would like to create a subclass of the class Alien, to simplify my code a bit. How would I do this? This is the code i have so far:
class Alien(pygame.sprite.Sprite):
def __init__(self, width, height):
super().__init__()
self.image = pygame.Surface([width, height])
self.image.fill(RED)
self.image = pygame.image.load("alien1.png").convert_alpha()
self.rect = self.image.get_rect()
In fact, you've just created a subclass of Sprite. Just do the same with Alien.
class Reptilian(Alien):
def __init__(self, width, height, human_form): # you can pass some other properties
super().__init__(width, height) # you must pass required args to Alien's __init__
# your custom stuff:
self.human_form = human_form
Related
I have a scene with QGraphicsPixmapItem, and show a QGraphicScene object like a rectangle.
def setupUI(self):
self.pixmap01 = QPixmap.fromImage(qImg)
self.mainpic = QGraphicsPixmapItem(self.pixmap01)
self.scene1.addItem(self.mainpic)
self.graphicsViewScene1.setScene(self.scene1)
self.scene1.update()
def DrawRectangle(self):
scene = RectangleScene()
scene.addItem(self.mainpic)
self.graphicsViewScene1.setScene(scene)
Now i a draw rectangle and top of a scene(this part of code is fine) but after right click on rect and choose replace pic item(option menu) i want to replace this selected area of QPixmap with another QPixmap(for this action i use Qpainter but nothing happens)
class RectangleScene(QGraphicsScene):
def __init__(self, *args, **kwargs):
super(RectangleScene, self).__init__(*args, **kwargs)
def mousePressEvent(self, event):
self.clean_scene()
self.start_point = event.scenePos()
self.end_point =self.start_point
self.graphics_line = QGraphicsRectItem(QRectF(self.start_point, self.end_point))
self.update_path()
def mouseMoveEvent(self, event):
self.end_point = event.scenePos()
self.update_path()
def mouseReleaseEvent(self, event):
self.end_point = event.scenePos()
self.update_path()
def update_path(self):
self.graphics_line.setRect(QRectF(self.start_point, self.end_point))
self.addItem(self.graphics_line)
def contextMenuEvent(self, event):
menu = QtWidgets.QMenu()
f1 = menu.addAction("repalce pic")
if action == f1:
tmp_rect = QRectF(self.start_point, self.end_point)
new_pix_map = QPixmap.fromImage(qImg)
painter = QPainter(self.imageProcessing.pixmap01)
painter.drawPixmap(tmp_rect,new_pix_map ,tmp_rect)
in another part of code after select this area, get a ndarray of this area and add some filters then i want to add top of this rect
I have found a code in realpython.com about python super() and I don't understand what is the purpose of the super() in Rectangle and Triangle init method if both classes have no parent (don't inherit).
class Rectangle:
def __init__(self, length, width, **kwargs):
self.length = length
self.width = width
super().__init__(**kwargs)
def area(self):
return self.length * self.width
class Square(Rectangle):
def __init__(self, length, **kwargs):
super().__init__(length=length, width=length, **kwargs)
class Triangle:
def __init__(self, base, height, **kwargs):
self.base = base
self.height = height
super().__init__(**kwargs)
def tri_area(self):
return 0.5 * self.base * self.height
class RightPyramid(Square, Triangle):
...
This way, these classes can work with multiple-inheritance, and they may get ancestors unknown at coding time - the call to super, passing any unknown parameters they may have got, ensures they will play nice when used this way.
For example, let's suppose these shapes are used to represent the creation concrete 3D printing plastic objects.
class Print3D:
def __init__(self, *, filament="PLA", **kw):
self.filament=filament
print("Print3D part initialized")
super().__init__(**kwargs)
One now can do:
class PrintedSquare(Square, Print3D):
pass
mysquare = PrintedSquare(length=20, filament="PVC")
and everything will just work.
I am learning PyQt5 recently and have problems when I want to delete a widget in QScrollArea. Is there an elegant way to visit the element in QScrollArea and delete it when the "delete" button in that element is clicked? Thank you for any help!
class MyWidget(QWidget):
def __init__(self, id):
super().__init__()
self.layout = QHBoxLayout()
self.layout.addWidget(QPlainTextEdit(id))
self.layout.addWidget(QPushButton('Delete'))
self.setLayout(self.layout)
# connect options
connect_options()
def connect_options(self):
pass
class MyList(QScrollArea):
def __init__(self):
super().__init__()
self.layout = QVBoxLayout()
self.widget = QWidget()
for x in range(10):
self.layout.addWidget(MyWidget(str(x)))
self.widget.setLayout(self.layout)
self.setMinimumSize(1024, 500)
self.setWidget(self.widget)
First I would suggest you look into QListWidget, It will provide you various functions to handle situations like this.
for your problem, you will need to delete the widget from its parent layout & then delete it from the GUI
class MyWidget(QWidget):
def __init__(self, id):
super().__init__()
self.layout = QHBoxLayout()
self.layout.addWidget(QPlainTextEdit(id))
del_btn = QPushButton('Delete')
del_btn.clicked.connect(self._delete) # connect the click event to your delete function
self.layout.addWidget(del_btn)
self.setLayout(self.layout)
# connect options
self.connect_options()
def connect_options(self):
pass
def _delete(self):
# here you will delete your widget
parent_layout = self.parent().layout()
parent_layout.removeWidget(self) # remove the widget from its parent layout
self.deleteLater() # lets Qt knows it needs to delete this widget from the GUI
del self
I am working on a Pygame game. The premise of the game is you must dodge obstacles that start at the bottom of the screen and move upward to create the illusion the player is falling. I already have a player sprite and need help with the obstacle class. When I try to initialize my Obstacle class, I get an error.
class Obstable(pg.sprite.Sprite):
def __init__(self, color, width):
pg.sprite.Sprite.__init__(self)
self.image = pygame.surface([width, 50])
self.image.fill(black)
self.rect = self.image.get_rect()
BLACK = (0,0,0)
obst1 = Obstacle(BLACK, 100)
The class is named Obstable, you instantiate it as Obstacle. Simple Typo.
Would be even easier if you included the NameError Exception. Saying "I get an Error" is not helpful.
Firstly, your class is named Obstable. See the problem? You will need to change it to Obstacle. This should fix problem number one. Once you fix this, and run your code, you should run into another mistake.
Your second problem appears to be that you are referencing an undefined variable in the Obstacle class.
class Obstable(pg.sprite.Sprite):
def __init__(self, color, width):
pg.sprite.Sprite.__init__(self)
self.image = pygame.surface([width, 50])
self.image.fill(black)
self.rect = self.image.get_rect()
The error is here:
self.image.fill(black)
The variable black is undefined. Instead, you need to change black to self.color, but before you can do that, you must initialize self.color. I fixed your code for you:
class Obstacle(pg.sprite.Sprite):
def __init__(self, color, width):
self.color = color
pg.sprite.Sprite.__init__(self)
self.image = pygame.surface([width, 50])
self.image.fill(self.color)
self.rect = self.image.get_rect()
BLACK = (0,0,0)
obst1 = Obstacle(BLACK, 100)
Hopefully my answer was of assistance to you!
I have a subclass of QGraphicsItem and I want to add instances of it to the scene on 'Control+LMB click'. The trouble is that the item is added at the position with coordinates that are two times larger than they should be. At the same time adding ellipses with scene.addEllipse(...) works fine.
#!/usr/bin/env python
import sys
from PyQt4.QtCore import (QPointF, QRectF, Qt, )
from PyQt4.QtGui import (QApplication, QMainWindow, QGraphicsItem,
QGraphicsScene, QGraphicsView, QPen, QStyle)
MapSize = (512, 512)
class DraggableMark(QGraphicsItem):
def __init__(self, position, scene):
super(DraggableMark, self).__init__(None, scene)
self.setFlags(QGraphicsItem.ItemIsSelectable | QGraphicsItem.ItemIsMovable)
self.rect = QRectF(position.x(), position.y(), 15, 15)
self.setPos(position)
scene.clearSelection()
def boundingRect(self):
return self.rect
def paint(self, painter, option, widget):
pen = QPen(Qt.SolidLine)
pen.setColor(Qt.black)
pen.setWidth(1)
if option.state & QStyle.State_Selected:
pen.setColor(Qt.blue)
painter.setPen(pen)
painter.drawEllipse(self.rect)
class GraphicsScene(QGraphicsScene):
def __init__(self, parent=None):
super(GraphicsScene, self).__init__(parent)
self.setSceneRect(0, 0, *MapSize)
def mousePressEvent(self, event):
super(GraphicsScene, self).mousePressEvent(event)
if event.button() != Qt.LeftButton:
return
modifiers = QApplication.keyboardModifiers()
pos = event.scenePos()
if modifiers == Qt.ControlModifier:
print("Control + Click: (%d, %d)" % (pos.x(), pos.y()))
DraggableMark(pos, self)
self.addEllipse(QRectF(pos.x(), pos.y(), 10, 10))
else:
print("Click: (%d, %d)" % (pos.x(), pos.y()))
class MainWindow(QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.scene = GraphicsScene(self)
self.scene.addRect(QRectF(0, 0, *MapSize), Qt.red)
self.view = QGraphicsView()
self.view.setScene(self.scene)
self.view.resize(self.scene.width(), self.scene.height())
self.setCentralWidget(self.view)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
rect = QApplication.desktop().availableGeometry()
window.resize(int(rect.width()), int(rect.height()))
window.show()
app.exec_()
I see you have answered your own question. However I would like to explain why this works.
Every QGraphicsItem has its own local coordinate system. So when you do
self.rect = QRectF(position.x(), position.y(), 15, 15)
you basically start from the (0, 0) of the item's local coordinate system and go to the given x and y which you take from position. This basically means that your rectangle will be drawn at position.x() + position.x() and position.y() + position.y() with the first position.x()/position.y() being the position of the QGraphicsItem inside your scene and the second position.x()/position.y() being the position inside the local coordinate system of your item.
If you want to start from the origin of the QGraphicsItem, you have to use
self.rect = QRectF(0, 0, 15, 15)
This ensures that you start from the origin of the local coordinate system.
This issue is particularly tricky due to the fact that by default objects are added to the (0, 0) of a scene. So position.x() + position.x() and position.y() + position.y() in this case will actually not show the issue at hand since 0+0 is always equal to 0. It is the moment you change the default position to something else when the problem will occur.
Here is a 3D figure that visualizes what I'm describing above (I was unable to find a 2D example but the principle is the same :P):
The world here is the scene while the object is the QGraphicsItem residing in that scene.
Changing
self.rect = QRectF(position.x(), position.y(), 15, 15)
to
self.rect = QRectF(0, 0, 15, 15)
solved the problem