How to use rubber band to zoom in and out in pyqt5 - python-3.x

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_())

Related

How can i draw interactively a line in QGraphicScene in PyQt5

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

Turtle screen gets closed when .onclick() or onscreenclick() is used

I have a global variable, 'is_game_on' set to 'False' to start with. I have a turtle which responds to .ondrag() function. My program works perfectly fine if I change the 'is_game_on' variable to 'True' (The main program runs in a while loop when 'is_game_on' is 'True').
In the same Screen I have created turtle (a text- 'Click to start') in the top right of the screen, which I want to return 'is_game_on' = 'True' when the mouse is clicked on it so that the rest of my program starts working there after. However, my screen gets closed when I click the mouse. I think this is because of the command screen.exitonclick() at the end. Appreciate any suggestions how to avoid this problem.
Below is my code. I want to start with 'is_game_on == False' and with the output a static display. Then when I click the mouse on 'Click to Start', a mechanism to trigger 'is_game_on" as True and then the ball starts bouncing up and down.
from turtle import Screen, Turtle
import time
# is_game_on = False
is_game_on = True
def click(i, j):
global is_game_on
if i >= 250 and j >= 300:
is_game_on = True
print(is_game_on)
return is_game_on
class Ball(Turtle):
def __init__(self):
super().__init__()
self.shape('circle')
self.color('black')
self.shapesize(stretch_wid=2, stretch_len=2)
self.penup()
self.speed(6)
self.goto(0, -355)
self.x_move = 0
self.y_move = 1
self.move_speed = 10
def move(self):
xcor_new = self.xcor() + self.x_move
ycor_new = self.ycor() + self.y_move
self.goto(xcor_new, ycor_new)
def bounce_y(self):
self.y_move *= -1
class Paddle(Turtle):
def __init__(self):
super().__init__()
self.shape('square')
self.penup()
self.goto(0, -380)
self.color('blue')
self.shapesize(stretch_wid=.5, stretch_len=10)
def move(self,i, j):
self.goto(i, -380)
class Start(Turtle):
def __init__(self):
super().__init__()
self.penup()
self.goto(250, 300)
self.color('blue')
self.shapesize(stretch_wid=4, stretch_len=10)
self.hideturtle()
self.write('Click to Start', font=('Arial', 35, 'bold'))
screen = Screen()
screen.colormode(255)
screen.bgcolor('white')
screen.setup(1200, 800)
screen.tracer(0)
paddle = Paddle()
ball = Ball()
screen.listen()
paddle.ondrag(paddle.move)
screen.onclick(click)
start = Start()
while is_game_on:
time.sleep(0)
screen.update()
ball.move()
if ball.ycor() >= 375:
ball.bounce_y()
if (abs(ball.xcor() - paddle.xcor()) < 120) and ball.ycor() == -355:
ball.bounce_y()
screen.update()
screen.exitonclick()
After lot of trial and errors and lot of web searches, I found the solution.
The screen closing problem can be simply avoided by importing turtle and adding turtle.done() command just before screen.exitonclick() command. The complete code will be.
from turtle import Screen, Turtle
import time
import turtle
is_game_on = False
# is_game_on = True
def click(i, j):
global is_game_on
if i >= 250 and j >= 300:
is_game_on = True
print(is_game_on)
return is_game_on
class Ball(Turtle):
def __init__(self):
super().__init__()
self.shape('circle')
self.color('black')
self.shapesize(stretch_wid=2, stretch_len=2)
self.penup()
self.speed(6)
self.goto(0, -355)
self.x_move = 0
self.y_move = 1
self.move_speed = 10
def move(self):
xcor_new = self.xcor() + self.x_move
ycor_new = self.ycor() + self.y_move
self.goto(xcor_new, ycor_new)
def bounce_y(self):
self.y_move *= -1
class Paddle(Turtle):
def __init__(self):
super().__init__()
self.shape('square')
self.penup()
self.goto(0, -380)
self.color('blue')
self.shapesize(stretch_wid=.5, stretch_len=10)
def move(self,i, j):
self.goto(i, -380)
class Start(Turtle):
def __init__(self):
super().__init__()
self.penup()
self.goto(250, 300)
self.color('blue')
self.shapesize(stretch_wid=4, stretch_len=10)
self.hideturtle()
self.write('Click to Start', font=('Arial', 35, 'bold'))
screen = Screen()
screen.colormode(255)
screen.bgcolor('white')
screen.setup(1200, 800)
screen.tracer(0)
paddle = Paddle()
ball = Ball()
screen.listen()
paddle.ondrag(paddle.move)
screen.onclick(click)
start = Start()
while is_game_on:
time.sleep(0)
screen.update()
ball.move()
if ball.ycor() >= 375:
ball.bounce_y()
if (abs(ball.xcor() - paddle.xcor()) < 120) and ball.ycor() == -355:
ball.bounce_y()
screen.update()
turtle.done()
screen.exitonclick()
The animation can work by moving the while loop into the click() function. The code will be as follows.
from turtle import Screen, Turtle
import time
import turtle
is_game_on = False
# is_game_on = True
def click(i, j):
global is_game_on
if i >= 250 and j >= 300:
is_game_on = True
print(is_game_on)
while is_game_on:
time.sleep(0)
screen.update()
ball.move()
if ball.ycor() >= 375:
ball.bounce_y()
if (abs(ball.xcor() - paddle.xcor()) < 120) and ball.ycor() == -355:
ball.bounce_y()
return is_game_on
class Ball(Turtle):
def __init__(self):
super().__init__()
self.shape('circle')
self.color('black')
self.shapesize(stretch_wid=2, stretch_len=2)
self.penup()
self.speed(6)
self.goto(0, -355)
self.x_move = 0
self.y_move = 1
self.move_speed = 10
def move(self):
xcor_new = self.xcor() + self.x_move
ycor_new = self.ycor() + self.y_move
self.goto(xcor_new, ycor_new)
def bounce_y(self):
self.y_move *= -1
class Paddle(Turtle):
def __init__(self):
super().__init__()
self.shape('square')
self.penup()
self.goto(0, -380)
self.color('blue')
self.shapesize(stretch_wid=.5, stretch_len=10)
def move(self,i, j):
self.goto(i, -380)
class Start(Turtle):
def __init__(self):
super().__init__()
self.penup()
self.goto(250, 300)
self.color('blue')
self.shapesize(stretch_wid=4, stretch_len=10)
self.hideturtle()
self.write('Click to Start', font=('Arial', 35, 'bold'))
screen = Screen()
screen.colormode(255)
screen.bgcolor('white')
screen.setup(1200, 800)
screen.tracer(0)
paddle = Paddle()
ball = Ball()
screen.listen()
paddle.ondrag(paddle.move)
screen.onclick(click)
start = Start()
screen.update()
turtle.done()
screen.exitonclick()

Drawing a circle on a QWidget python GUI

I'm trying to draw a circle instead of dots
Here is the class where it paints red dots on pressing event at any place in the widget
I want to draw a circle (hollow circle) as an outline not a solid circle that hide part of my picture
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
class Canvas(QWidget):
def __init__(self, photo, *args, **kwargs):
super().__init__(*
args, **kwargs)
self.image = QImage(photo)
self.setFixedSize(self.image.width(), self.image.height())
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton:
qp = QPainter(self.image)
qp.setRenderHint(QPainter.Antialiasing)
qp.setPen(QPen(Qt.red, 5))
qp.setBrush(Qt.red)
qp.drawPoint(event.pos())
self.update()
def paintEvent(self, event):
qp = QPainter(self)
rect = event.rect()
qp.drawImage(rect, self.image, rect)
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
w = QWidget()
self.setCentralWidget(w)
grid = QGridLayout(w)
grid.addWidget(Canvas('photo.jpeg'))
if __name__ == '__main__':
app = QApplication(sys.argv)
gui = MainWindow()
gui.show()
sys.exit(app.exec_())
I believe this is what you're trying to do.
In which case you need to take advantage of which paint device to pass to QPainter. During mousePressEvent and mouseMoveEvent use QPainter(self) so anything painted will only last until the next update. Then in mouseReleaseEvent when satisfied with the size of the circle, you can paint on the QImage with QPainter(self.image) to permanently draw the circle.
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
class Canvas(QWidget):
def __init__(self, photo, *args, **kwargs):
super().__init__(*args, **kwargs)
self.image = QImage(photo)
self.setFixedSize(self.image.width(), self.image.height())
self.pressed = self.moving = False
self.revisions = []
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton:
self.pressed = True
self.center = event.pos()
self.update()
def mouseMoveEvent(self, event):
if event.buttons() & Qt.LeftButton:
self.moving = True
r = (event.pos().x() - self.center.x()) ** 2 + (event.pos().y() - self.center.y()) ** 2
self.radius = r ** 0.5
self.update()
def mouseReleaseEvent(self, event):
if event.button() == Qt.LeftButton:
self.revisions.append(self.image.copy())
qp = QPainter(self.image)
self.draw_circle(qp) if self.moving else self.draw_point(qp)
self.pressed = self.moving = False
self.update()
def paintEvent(self, event):
qp = QPainter(self)
rect = event.rect()
qp.drawImage(rect, self.image, rect)
if self.moving:
self.draw_circle(qp)
elif self.pressed:
self.draw_point(qp)
def draw_point(self, qp):
qp.setPen(QPen(Qt.black, 5))
qp.drawPoint(self.center)
def draw_circle(self, qp):
qp.setRenderHint(QPainter.Antialiasing)
qp.setPen(QPen(Qt.black, 3, Qt.DashLine))
qp.drawEllipse(self.center, self.radius, self.radius)
def undo(self):
if self.revisions:
self.image = self.revisions.pop()
self.update()
def reset(self):
if self.revisions:
self.image = self.revisions[0]
self.revisions.clear()
self.update()
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
w = QWidget()
self.setCentralWidget(w)
canvas = Canvas('photo.png')
grid = QGridLayout(w)
grid.addWidget(canvas)
QShortcut(QKeySequence('Ctrl+Z'), self, canvas.undo)
QShortcut(QKeySequence('Ctrl+R'), self, canvas.reset)
if __name__ == '__main__':
app = QApplication(sys.argv)
gui = MainWindow()
gui.show()
sys.exit(app.exec_())

How to change a QImage that is already set up and shown within QWidget?

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()

Adding scrollbar in pyqt4

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

Resources