I have some large images to be inserted in window and my window size is defined. If my image size is greater than window, there must be scroll bars else not. I have also panning and zooming features implemented so that i can resize image to any size. Thanks antiearth for this sample code
from PyQt4 import QtCore, QtGui
import sys
class Annotator(QtGui.QWidget):
def __init__(self):
QtGui.QWidget.__init__(self)
self.image = None
self.scale = 1.0
self.position = (100, 100)
self.pressed = None
self.anchor = None
self.load('Some LArge Image/Images.png')
def load(self, filename):
self.image = QtGui.QImage(filename)
def mousePressEvent(self, event):
print 'PRESSED : ',event.pos()
self.pressed = event.pos()
self.anchor = self.position
def mouseReleaseEvent(self, event):
self.pressed = None
def mouseMoveEvent(self, event):
if (self.pressed):
dx, dy = event.x() - self.pressed.x(), event.y() - self.pressed.y()
self.position = (self.anchor[0] - dx, self.anchor[1] - dy)
self.repaint()
def wheelEvent(self, event):
oldscale = self.scale
self.scale += event.delta() / 1200.0
if (self.scale < 0.1):
self.scale = oldscale
screenpoint = self.mapFromGlobal(QtGui.QCursor.pos())
dx, dy = screenpoint.x(), screenpoint.y()
oldpoint = (screenpoint.x() + self.position[0], screenpoint.y() + self.position[1])
newpoint = (oldpoint[0] * (self.scale/oldscale),
oldpoint[1] * (self.scale/oldscale))
self.position = (newpoint[0] - dx, newpoint[1] - dy)
self.repaint()
def paintEvent(self, event):
painter = QtGui.QPainter()
painter.begin(self)
painter.drawImage(0, 0,
self.image.scaled(
self.image.width() * self.scale,
self.image.height() * self.scale,
QtCore.Qt.KeepAspectRatio),
self.position[0], self.position[1])
painter.end()
app = QtGui.QApplication(sys.argv)
annotator = Annotator()
annotator.show()
sys.exit(app.exec_())
I want to insert scrollbars here. Hope I made this clear.
In PyQt4 have QtGui.QScrollArea to allow your resize with scroll bars, So your have to implement this class and in your def paintEvent (self, eventQPaintEvent) your have calculate new position and resize your widget with QWidget.setFixedSize (self, QSize)
Full example;
from PyQt4 import QtCore, QtGui
import sys
class Annotator (QtGui.QLabel):
def __init__(self, parentQExampleScrollArea, parentQWidget = None):
QtGui.QLabel.__init__(self, parentQWidget)
self.parentQExampleScrollArea = parentQExampleScrollArea
self.image = None
self.scale = 1.0
self.position = (0, 0)
self.pressed = None
self.anchor = None
self.load('myImage.jpg')
def load (self, filename):
self.image = QtGui.QImage(filename)
def mousePressEvent (self, eventQMouseEvent):
self.pressed = eventQMouseEvent.pos()
self.anchor = self.position
def mouseReleaseEvent (self, eventQMouseEvent):
self.pressed = None
def mouseMoveEvent (self, eventQMouseEvent):
if (self.pressed):
dx, dy = eventQMouseEvent.x() - self.pressed.x(), eventQMouseEvent.y() - self.pressed.y()
self.position = (self.anchor[0] - dx, self.anchor[1] - dy)
self.repaint()
def wheelEvent (self, eventQWheelEvent):
oldscale = self.scale
self.scale += eventQWheelEvent.delta() / 1200.0
if (self.scale < 0.1):
self.scale = oldscale
screenpoint = self.mapFromGlobal(QtGui.QCursor.pos())
dx, dy = screenpoint.x(), screenpoint.y()
oldpoint = (screenpoint.x() + self.position[0], screenpoint.y() + self.position[1])
newpoint = (oldpoint[0] * (self.scale/oldscale), oldpoint[1] * (self.scale/oldscale))
self.position = (newpoint[0] - dx, newpoint[1] - dy)
self.repaint()
def paintEvent (self, eventQPaintEvent):
scaledQImage = self.image.scaled (
self.image.width() * self.scale,
self.image.height() * self.scale,
QtCore.Qt.KeepAspectRatio)
painter = QtGui.QPainter()
painter.begin(self)
painter.drawImage (
0,
0,
scaledQImage,
0 if self.position[0] > 0 else self.position[0],
0 if self.position[1] > 0 else self.position[1])
painter.end()
scaledWidth = self.parentQExampleScrollArea.size().width() - 16 if self.position[0] > 0 else scaledQImage.width()
scaledHeight = self.parentQExampleScrollArea.size().height() - 16 if self.position[1] > 0 else scaledQImage.height()
self.setFixedSize(abs(self.position[0]) + scaledWidth, abs(self.position[1]) + scaledHeight)
class QExampleScrollArea (QtGui.QScrollArea):
def __init__ (self, parentQWidget = None):
super(QtGui.QScrollArea, self).__init__(parentQWidget)
self.myAnnotator = Annotator(self)
self.setWidget(self.myAnnotator)
def mousePressEvent (self, eventQMouseEvent):
QtGui.QScrollArea.mousePressEvent(self, eventQMouseEvent)
self.myAnnotator.mousePressEvent(eventQMouseEvent)
def mouseReleaseEvent (self, eventQMouseEvent):
QtGui.QScrollArea.mouseReleaseEvent(self, eventQMouseEvent)
self.myAnnotator.mouseReleaseEvent(eventQMouseEvent)
def mouseMoveEvent (self, eventQMouseEvent):
QtGui.QScrollArea.mouseMoveEvent(self, eventQMouseEvent)
self.myAnnotator.mouseMoveEvent(eventQMouseEvent)
def wheelEvent (self, eventQWheelEvent):
self.myAnnotator.wheelEvent(eventQWheelEvent)
app = QtGui.QApplication(sys.argv)
myQExampleScrollArea = QExampleScrollArea()
myQExampleScrollArea.show()
sys.exit(app.exec_())
Note : Recommend use QtGui.QLabel to paint image
Related
I'm trying to draw a line interactively but I can't figure out how to do it. Anyone can help me?
I'm using PyQt5. I create a QGraphicsScene, I override mouse press event but when I try to draw the draw the it draw nothing.
Finally, I have another question. How can I snap this line to the grid?
import math
import sys
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
class neGraphicScene(QGraphicsScene):
_colorBackGround: str
_colorLightLines: str
_colorDarkLines: str
_penLight: QPen
_penDark: QPen
gridSize: int = 20
gridSquares: int = 5
isLineDrawing = False
def __init__(self, parent=None):
QGraphicsScene.__init__(self, QRectF(-1000, -1000, 2000, 2000), parent)
self.setSceneColor()
self.begin, self.destination = QPoint(), QPoint()
def setSceneColor(self, _lightLines="#2f2f2f", _darkLines="#292929", _background="#393939"):
self._colorBackGround = _background
self._colorLightLines = _lightLines
self._colorDarkLines = _darkLines
self._penLight = QPen(QColor(self._colorLightLines))
self._penLight.setWidth(1)
self._penDark = QPen(QColor(self._colorDarkLines))
self._penDark.setWidth(2)
self.setBackgroundBrush(QColor(self._colorBackGround))
def setGraphicScene(self, width, height):
self.setSceneRect(-width // 2, -height // 2, width, height)
def mouseDoubleClickEvent(self, event):
QGraphicsScene.mouseMoveEvent(self, event)
def mousePressEvent(self, event):
self.isLineDrawing = True
if event.buttons() & Qt.LeftButton:
print('Point 1')
self.begin = event.pos()
self.destination = self.begin
self.update()
def mouseMoveEvent(self, event):
if event.buttons() & Qt.LeftButton:
print('Point 2')
self.destination = event.pos()
self.update()
def mouseReleaseEvent(self, event):
self.isLineDrawing = False
print('Point 3')
def drawBackground(self, painter, rect):
super(neGraphicScene, self).drawBackground(painter, rect)
# self.drawBackgroundGrid(painter, rect)
if self.isLineDrawing:
if not self.begin.isNull() and not self.destination.isNull():
line = QLineF(self.begin, self.destination)
painter.setPen(Qt.red)
painter.drawLine(line)
This is the QGraphicsView and the QWidgetStuff to made the minimal example working properly:
class neGraphicView(QGraphicsView):
def __init__(self, graphicScene, parent=None):
super().__init__(parent)
# self._dragPos = QPoint(0, 0)
self.sharedGraphicScene = graphicScene
self.setScene(self.sharedGraphicScene)
self._mousePressed = False
self._isPanning = False
self.initUI()
def initUI(self):
self.setRenderHints(
QPainter.Antialiasing | QPainter.HighQualityAntialiasing |
QPainter.TextAntialiasing | QPainter.SmoothPixmapTransform)
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.setDragMode(QGraphicsView.RubberBandDrag)
class NodeEditorWindow(QWidget):
mainLayout: QVBoxLayout
mainGraphicsScene: neGraphicScene
view: neGraphicView
def __init__(self, parent=None):
super(NodeEditorWindow, self).__init__(parent)
self.initUI()
def initUI(self):
self.setGeometry(200, 200, 800, 600)
self.mainLayout = QVBoxLayout()
self.mainLayout.setContentsMargins(0, 0, 0, 0)
self.setLayout(self.mainLayout)
self.mainGraphicsScene = neGraphicScene()
self.view = neGraphicView(self.mainGraphicsScene, self)
self.mainLayout.addWidget(self.view)
self.setWindowTitle("Node Editor")
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
app.setStyle("Fusion")
win = NodeEditorWindow()
win.show()
sys.exit(app.exec())
This is the grid function:
def drawBackgroundGrid(self, _painter, _rect):
# here we create our grid
_left = int(math.floor(_rect.left()))
_right = int(math.ceil(_rect.right()))
_top = int(math.floor(_rect.top()))
_bottom = int(math.ceil(_rect.bottom()))
first_left = _left - (_left % self.gridSize)
first_top = _top - (_top % self.gridSize)
try:
# compute all lines to be drawn
lightLines, darkLines = [], []
for x in range(first_left, _right, self.gridSize):
if x % (self.gridSize * self.gridSquares) != 0:
lightLines.append(QLineF(x, _top, x, _bottom))
else:
darkLines.append(QLineF(x, _top, x, _bottom))
for y in range(first_top, _bottom, self.gridSize):
if y % (self.gridSize * self.gridSquares) != 0:
lightLines.append(QLineF(_left, y, _right, y))
else:
darkLines.append(QLineF(_left, y, _right, y))
# draw the lines
_painter.setPen(self._penLight)
_painter.drawLines(*lightLines)
_painter.setPen(self._penDark)
_painter.drawLines(*darkLines)
except Exception as e:
# print(e)
pass
I would like to use the RubberBand to zoom in and out relative to the size of the box I would like to zoom in the view to fit whatever is inside the block to the full view.
Can anyone help?
The zoom in and out with the mouse works as expected.
You can see in the code the rubberband works but I don't know how to make the zoom relative to the size of the box.
code:
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
import sys
from math import sqrt
class Point(QGraphicsItem):
def __init__(self, x, y):
super(Point, self).__init__()
self.setFlag(QGraphicsItem.ItemIsSelectable, True)
self.rectF = QRectF(0, 0, 30, 30)
self.x=x
self.y=y
self._brush = QBrush(Qt.black)
def setBrush(self, brush):
self._brush = brush
self.update()
def boundingRect(self):
return self.rectF
def paint(self, painter=None, style=None, widget=None):
painter.fillRect(self.rectF, self._brush)
def hoverMoveEvent(self, event):
point = event.pos().toPoint()
print(point)
QGraphicsItem.hoverMoveEvent(self, event)
class Viewer(QGraphicsView):
photoClicked = pyqtSignal(QPoint)
rectChanged = pyqtSignal(QRect)
def __init__(self, parent):
super(Viewer, self).__init__(parent)
self.rubberBand = QRubberBand(QRubberBand.Rectangle, self)
self.setMouseTracking(True)
self.origin = QPoint()
self.changeRubberBand = False
self._zoom = 0
self._empty = True
self._scene = QGraphicsScene(self)
self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse)
self.setResizeAnchor(QGraphicsView.AnchorUnderMouse)
self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.setFrameShape(QFrame.NoFrame)
self.area = float()
self.setPoints()
def setItems(self):
self.data = {'x': [-2414943.8686, -2417160.6592, -2417160.6592, -2417856.1783, -2417054.7618, -2416009.9966, -2416012.5232, -2418160.8952, -2418160.8952, -2416012.5232, -2417094.7694, -2417094.7694], 'y': [10454269.7008,
10454147.2672, 10454147.2672, 10453285.2456, 10452556.8132, 10453240.2808, 10455255.8752, 10455183.1912, 10455183.1912, 10455255.8752, 10456212.5959, 10456212.5959]}
maxX = max(self.data['x'])
minX = min(self.data['x'])
maxY = max(self.data['y'])
minY = min(self.data['y'])
distance = sqrt((maxX-minX)**2+(maxY-minY)**2)
self.area = QRectF(minX, minY, distance, distance)
for i,x in enumerate(self.data['x']):
x = self.data['x'][i]
y = self.data['y'][i]
p = Point(x,y)
p.setPos(x,y)
self._scene.addItem(p)
self.setScene(self._scene)
def fitInView(self, scale=True):
rect = QRectF(self.area)
if not rect.isNull():
self.setSceneRect(rect)
unity = self.transform().mapRect(QRectF(0, 0, 1, 1))
self.scale(1 / unity.width(), 1 / unity.height())
viewrect = self.viewport().rect()
scenerect = self.transform().mapRect(rect)
factor = min(viewrect.width() / scenerect.width(),
viewrect.height() / scenerect.height())
self.scale(factor, factor)
self._zoom = 0
def setPoints(self):
self._zoom = 0
self.setItems()
self.setDragMode(True)
self.fitInView()
def wheelEvent(self, event):
if event.angleDelta().y() > 0:
factor = 1.25
self._zoom += 1
else:
factor = 0.8
self._zoom -= 1
if self._zoom > 0:
self.scale(factor, factor)
elif self._zoom == 0:
self.fitInView()
else:
self._zoom = 0
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton:
self.origin = event.pos()
self.rubberBand.setGeometry(QRect(self.origin, QSize()))
self.rectChanged.emit(self.rubberBand.geometry())
self.rubberBand.show()
self.changeRubberBand = True
return
#QGraphicsView.mousePressEvent(self,event)
elif event.button() == Qt.MidButton:
self.viewport().setCursor(Qt.ClosedHandCursor)
self.original_event = event
handmade_event = QMouseEvent(QEvent.MouseButtonPress,QPointF(event.pos()),Qt.LeftButton,event.buttons(),Qt.KeyboardModifiers())
QGraphicsView.mousePressEvent(self,handmade_event)
super(Viewer, self).mousePressEvent(event)
def mouseReleaseEvent(self, event):
if event.button() == Qt.LeftButton:
self.origin = event.pos()
self.rubberBand.setGeometry(QRect(self.origin, QSize()))
self.changeRubberBand = False
QGraphicsView.mouseReleaseEvent(self,event)
elif event.button() == Qt.MidButton:
self.viewport().setCursor(Qt.OpenHandCursor)
handmade_event = QMouseEvent(QEvent.MouseButtonRelease,QPointF(event.pos()),Qt.LeftButton,event.buttons(),Qt.KeyboardModifiers())
QGraphicsView.mouseReleaseEvent(self,handmade_event)
super(Viewer, self).mouseReleaseEvent(event)
def mouseMoveEvent(self, event):
if self.changeRubberBand:
self.rubberBand.setGeometry(QRect(self.origin, event.pos()).normalized())
self.rectChanged.emit(self.rubberBand.geometry())
QGraphicsView.mouseMoveEvent(self,event)
super(Viewer, self).mouseMoveEvent(event)
class Window(QWidget):
def __init__(self):
super(Window, self).__init__()
self.viewer = Viewer(self)
self.btnLoad = QToolButton(self)
self.btnLoad.setText('Load Points')
self.btnLoad.clicked.connect(self.loadPoints)
VBlayout = QVBoxLayout(self)
VBlayout.addWidget(self.viewer)
HBlayout = QHBoxLayout()
HBlayout.setAlignment(Qt.AlignLeft)
HBlayout.addWidget(self.btnLoad)
VBlayout.addLayout(HBlayout)
def loadPoints(self):
self.viewer.setPoints()
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
window = Window()
window.setGeometry(500, 300, 800, 600)
window.show()
sys.exit(app.exec_())
in my code I have two comboboxes inside and I intentionally designed a frameless borderless window; so I had to define mouse events manually to move window on click and drag, and resizing on edges.
without comboboxes it works perfectly, but somehow clicking on combos to open them trigger only mouseMoveEvent and not mousePressEvent, causing an error about there is no self.old_Pos. if we uncomment last three lines of init function, this error is gone, but on openning combos whole window will be displaced. how can I overcome this problem?
from PyQt5.QtWidgets import *
from PyQt5 import QtCore
from PyQt5.QtCore import *
from PyQt5.QtGui import *
class MainWindow(QWidget):
switch_window = QtCore.pyqtSignal()
def __init__(self):
QWidget.__init__(self)
self.combo1 = QComboBox()
for i in range (0,10):
self.combo1.addItem('Combo1 label %s' %str(i))
self.combo2 = QComboBox()
for i in range (0,15):
self.combo2.addItem('Combo1 label %s' %str(i))
main_layout = QVBoxLayout()
layout = QHBoxLayout()
layout.addWidget(self.combo1)
layout.addWidget(self.combo2)
# design title bar
title_bar = QHBoxLayout()
title_bar.setObjectName('HeaderBar')
title_bar.setContentsMargins(0,0,0,0)
title = QLabel('title bar')
btn_size = 35
btn_close = QPushButton("x")
btn_close.clicked.connect(self.btn_close_clicked)
btn_close.setFixedSize(btn_size,btn_size)
btn_close.setStyleSheet("background-color: red;")
btn_min = QPushButton("_")
btn_min.clicked.connect(self.btn_min_clicked)
btn_min.setFixedSize(btn_size, btn_size)
btn_min.setStyleSheet("background-color: gray;")
self.btn_max = QPushButton("+")
self.btn_max.clicked.connect(self.btn_max_clicked)
self.btn_max.setFixedSize(btn_size, btn_size)
self.btn_max.setStyleSheet("background-color: gray;")
title.setAlignment(Qt.AlignCenter)
title_bar.addWidget(title)
title_bar.addWidget(btn_min)
title_bar.addWidget(self.btn_max)
title_bar.addWidget(btn_close)
main_layout.addLayout(title_bar)
main_layout.addLayout(layout)
self.setWindowFlags(Qt.FramelessWindowHint)
self.setLayout(main_layout)
#self.old_Pos = QPoint(0,0)
#self.old_width = self.width()
#self.old_height = self.height()
def mousePressEvent(self, event):
self.old_Pos = event.globalPos()
self.old_width = self.width()
self.old_height = self.height()
def mouseMoveEvent(self, event):
delta = QPoint (event.globalPos() - self.old_Pos)
if (self.old_Pos.x() > self.x() + self.old_width - 10) or (self.old_Pos.y() > self.y() + self.old_height - 10):
self.setFixedSize(self.old_width + delta.x(),self.old_height + delta.y())
else:
self.move(self.x() + delta.x(), self.y() + delta.y())
self.old_Pos = event.globalPos()
def btn_close_clicked(self):
quit()
def btn_max_clicked(self):
if self.isMaximized():
self.showNormal()
self.btn_max.setText('+')
else:
self.showMaximized()
self.btn_max.setText('R')
def btn_min_clicked(self):
self.showMinimized()
app = QApplication([])
mainapp = MainWindow()
mainapp.show()
app.exec_()
I believe I solved this problem.
all we have to do is to define self.old_Pos = None inside __init__ and mouseReleaseEvent, and put an if self.old_Pos: statement inside mouseMoveEvent.
here is the code:
from PyQt5.QtWidgets import *
from PyQt5 import QtCore
from PyQt5.QtCore import *
from PyQt5.QtGui import *
class MainWindow(QWidget):
switch_window = QtCore.pyqtSignal()
def __init__(self):
QWidget.__init__(self)
self.combo1 = QComboBox()
for i in range (0,10):
self.combo1.addItem('Combo1 label %s' %str(i))
self.combo2 = QComboBox()
for i in range (0,15):
self.combo2.addItem('Combo2 label %s' %str(i))
main_layout = QVBoxLayout()
layout = QHBoxLayout()
layout.addWidget(self.combo1)
layout.addWidget(self.combo2)
# design title bar
title_bar = QHBoxLayout()
title_bar.setObjectName('HeaderBar')
title_bar.setContentsMargins(0,0,0,0)
title = QLabel('title bar')
btn_size = 35
btn_close = QPushButton("x")
btn_close.clicked.connect(self.btn_close_clicked)
btn_close.setFixedSize(btn_size,btn_size)
btn_close.setStyleSheet("background-color: red;")
btn_min = QPushButton("_")
btn_min.clicked.connect(self.btn_min_clicked)
btn_min.setFixedSize(btn_size, btn_size)
btn_min.setStyleSheet("background-color: gray;")
self.btn_max = QPushButton("+")
self.btn_max.clicked.connect(self.btn_max_clicked)
self.btn_max.setFixedSize(btn_size, btn_size)
self.btn_max.setStyleSheet("background-color: gray;")
title.setAlignment(Qt.AlignCenter)
title_bar.addWidget(title)
title_bar.addWidget(btn_min)
title_bar.addWidget(self.btn_max)
title_bar.addWidget(btn_close)
main_layout.addLayout(title_bar)
main_layout.addLayout(layout)
self.setWindowFlags(Qt.FramelessWindowHint)
self.setLayout(main_layout)
self.work_with_combo = True
self.old_Pos = None
def mousePressEvent(self, event):
self.old_Pos = event.globalPos()
self.old_width = self.width()
self.old_height = self.height()
def mouseMoveEvent(self, event):
if self.old_Pos:
delta = QPoint (event.globalPos() - self.old_Pos)
if (self.old_Pos.x() > self.x() + self.old_width - 10) or (self.old_Pos.y() > self.y() + self.old_height - 10):
self.setFixedSize(self.old_width + delta.x(),self.old_height + delta.y())
else:
self.move(self.x() + delta.x(), self.y() + delta.y())
self.old_Pos = event.globalPos()
def mouseReleaseEvent(self, event):
self.old_Pos = None
def btn_close_clicked(self):
quit()
def btn_max_clicked(self):
if self.isMaximized():
self.showNormal()
self.btn_max.setText('+')
else:
self.showMaximized()
self.btn_max.setText('R')
def btn_min_clicked(self):
self.showMinimized()
app = QApplication([])
mainapp = MainWindow()
mainapp.show()
app.exec_()
I have been searching for this solution FOREVER. Just wanted to thank you so much for posting the solution. Worked perfectly for me!
For anyone using just Qt Creator, here is the ultimate code I used:
//Declare oldPos in .h private
QPoint oldPos = QPoint();
void GiftCardDialog::mousePressEvent(QMouseEvent* event) {
oldPos = event->globalPos();
}
void GiftCardDialog::mouseReleaseEvent(QMouseEvent *event) {
(void)event;
oldPos = QPoint();
}
void GiftCardDialog::mouseMoveEvent(QMouseEvent* event) {
if(!oldPos.isNull()) {
QPoint delta = event->globalPos() - oldPos;
if(oldPos.x() > this->x() + this->width() - 10
|| oldPos.y() > this->y() + this->height() - 10) {
} else {
move(this->x() + delta.x(), this->y() + delta.y());
oldPos = event->globalPos();
}
}
}
I want to change an image with my mouse. So, everytime I click somewhere, the image should change. I can show an image only one time. So I need to separate the initialization of everything that is needed to show an image from the part of code that is responsable for building an image.
Here is what I have got by far
import sys
from PyQt4.QtGui import *
from PyQt4.QtCore import pyqtSlot
class Example(QWidget):
def __init__(self):
super(Example, self).__init__()
self.gx=1
self.gy=1
self.tlb=QLabel()
self.lbl=QLabel()
self.image = QImage(512, 512, QImage.Format_RGB32)
self.hbox = QHBoxLayout()
self.pixmap = QPixmap()
self.initUI()
def mousePressEvent(self, QMouseEvent):
px = QMouseEvent.pos().x()
py = QMouseEvent.pos().y()
size = self.frameSize()
self.gx = px-size.width()/2
self.gy = py-size.height()/2
self.fillImage()
def initUI(self):
self.hbox = QHBoxLayout(self)
self.pixmap = QPixmap()
size = self.frameSize()
self.fillImage()
self.lbl = QLabel(self)
self.lbl.setPixmap(self.pixmap)
self.hbox.addWidget(self.lbl)
self.setLayout(self.hbox)
self.move(300, 200)
self.setWindowTitle('Red Rock')
self.tlb = QLabel(str(self.gx)+" : "+str(self.gy), self)
self.tlb.move(12,3)
self.show()
def fillImage(self):
for x in range(0, 512):
t = -1+(x/512)*2
color = (1 - (3 - 2*abs(t))*t**2)
for y in range(0, 512):
t1 = -1+(y/512)*2
color1 = (1 - (3 - 2*abs(t1))*t1**2)
result = (255/2)+(color * color1 * (t*self.gx+t1*self.gy) )*(255/2)
self.image.setPixel(x, y, qRgb(result, result, result))
self.pixmap = self.pixmap.fromImage(self.image)
self.tlb = QLabel(str(self.gx)+" : "+str(self.gy), self)
print(self.gx)
self.update()
def main():
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
The print(self.gx) shows me that self.gx is changed, but the image isn't changed at all.
What do I do wrong?
You will have to tell the GUI that it needs to refresh the image.
In QT it seems you will need to call the update() or repaint() methods of the widget.
I've added self.lbl.setPixmap(self.pixmap) into fillImage before self.repaint() and self.update() and now it works, then i changed a little the code and now it looks like this
import sys
from PyQt4.QtGui import *
from PyQt4.QtCore import pyqtSlot
class Example(QWidget):
def __init__(self):
super(Example, self).__init__()
self.gx=1
self.gy=1
self.lbl=QLabel()
self.tlb = None
self.image = QImage(512, 512, QImage.Format_RGB32)
self.hbox = QHBoxLayout()
self.pixmap = QPixmap()
self.length = 1
self.initUI()
def mousePressEvent(self, QMouseEvent):
px = QMouseEvent.pos().x()
py = QMouseEvent.pos().y()
size = self.frameSize()
self.gx = px-size.width()/2
self.gy = py-size.height()/2
h = (self.gx**2+self.gy**2)**0.5
self.gx/=h
self.gy/=h
self.gx*=self.length
self.gy*=self.length
self.fillImage()
def wheelEvent(self,event):
self.length+=(event.delta()*0.001)
print(self.length)
def initUI(self):
self.hbox = QHBoxLayout(self)
self.pixmap = QPixmap()
self.move(300, 200)
self.setWindowTitle('Red Rock')
self.addedWidget = None
self.fillImage()
self.setLayout(self.hbox)
self.show()
def fillImage(self):
for x in range(0, 512):
t = -1+(x/512)*2
color = (1 - (3 - 2*abs(t))*t**2)
for y in range(0, 512):
t1 = -1+(y/512)*2
color1 = (1 - (3 - 2*abs(t1))*t1**2)
result = (255/2)+(color * color1 * (t*self.gx+t1*self.gy) )*(255/2)
self.image.setPixel(x, y, qRgb(result, result, result))
self.pixmap = self.pixmap.fromImage(self.image)
if self.lbl == None:
self.lbl = QLabel(self)
else:
self.lbl.setPixmap(self.pixmap)
if self.addedWidget == None:
self.hbox.addWidget(self.lbl)
self.addedWidget = True
if self.tlb==None:
self.tlb = QLabel(str(self.gx)+" : "+str(self.gy), self)
self.tlb.move(12,3)
else:
self.tlb.setText(str(self.gx)+" : "+str(self.gy))
self.repaint()
self.update()
def main():
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
I've been trying to work this out for a while now. Below, is the python/kivy code for the early stages of a kivy app. The issue lies in player movement. Kivy is overcompensating the dx and dy movements and it is causing the player movement to constantly shake. I don't know how to fix this issue. Any ideas?
Note:
Much of this code is incomplete, but the player movement is mostly done. The movement issue is happening in the "Player" class.
EDIT: Here is what I tried following the advice of the post below
import kivy
kivy.require('1.1.1')
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.properties import ObjectProperty, ListProperty, NumericProperty
import math
from kivy.clock import Clock
import time
import random
PLAYER_SPEED = 10
ENEMY_SPAWN = 3
UPDATE_SPEED = .01
MIN_INITIAL_PLAYER_MINION_DISTANCE = 200
class Player(Widget):
velocity_x = NumericProperty(0)
velocity_y = NumericProperty(0)
target = ListProperty([])
speed = NumericProperty(PLAYER_SPEED)
def __init__(self, **kwargs):
Widget.__init__(self)
self.target = [399.0, 399.0]
def update_target(self, new_target):
self.target = new_target
def move(self):
dx = self.target[0] - self.center[0]
dy = self.target[1] - self.center[1]
x_1 = self.pos[0] - self.center[0]
y_1 = self.pos[1] - self.center[1]
total = math.sqrt(dx ** 2 + dy**2)
self.velocity_x = (dx / total) * self.speed
self.velocity_y = (dy / total) * self.speed
if math.sqrt(x_1** 2 + y_1**2) < self.speed:
self.pos = self.center
else:
new_x = self.pos[0] + self.velocity_x
new_y = self.pos[1] + self.velocity_y
self.pos = (new_x,new_y)
class Enemy(Player):
velocity_y = NumericProperty(PLAYER_SPEED)
def __init__(self, **kwargs):
Widget.__init__(self)
self.center = kwargs.get('start_pos',[0,0])
def move(self):
self.pos = (self.pos[0], self.pos[1] + self.velocity_y)
def distance(widget1, widget2):
dist = math.sqrt((widget1.pos[0]-widget2.pos[0])**2 + \
(widget1.pos[1]-widget2.pos[1])**2)
return dist
class Game(Widget):
player1 = ObjectProperty(None)
enemies = ListProperty([])
decoys = ListProperty([])
def setup(self):
self.enemies = []
self.decoys = []
self.player1.center = self.center
self.setup_schedules()
#Don't forget about good code organization!
def setup_schedules(self):
Clock.schedule_interval(self.update, UPDATE_SPEED)
Clock.schedule_interval(self.spawn_enemy, ENEMY_SPAWN)
def update(self,dt):
self.player1.move()
def spawn_enemy(self, dt):
x = float(random.randint(0, self.width))
y = float(random.randint(0, self.height))
enemy = Enemy(start_pos = (x,y))
while distance(enemy, self.player1)< MIN_INITIAL_PLAYER_MINION_DISTANCE:
x = float(random.randint(0, self.width))
y = float(random.randint(0, self.height))
enemy.pos = (x,y)
self.enemies.append(enemy)
self.add_widget(enemy)
def score(self):
zero_score = time.time()
player_score = zero_score + 1
#on_touch_move vs on_touch_down
def on_touch_move(self, touch):
self.player1.update_target([touch.x, touch.y])
#Entry Point into app
class GameApp(App):
def build(self):
game = Game()
game.setup()
return game
def main():
GameApp().run()
main()
In your player class, and within move(), before you update pos, you would check if the distance between pos and center is smaller than speed. if it is, then simply set pos to be equal to center. If it is not, then increment pos as you already do.