esdairim | 2020-11-12 21:00:18 UTC | #1
Hello everyone, I got this code that helps me draw a rectangle, I'd like to be able to drag the left and right sides of the rectangle to adjust the width of the rectangle, make the rectangle behave in a way similar to how you crop an image on most photo editing software, where you draw the initial area but you have the possibility to adjust the width afterwards to get the crop you want. Thank you for your help. the code I have so far:
import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
class MyWidget(QWidget):
def __init__(self):
super().__init__()
self.setGeometry(30,30,600,400)
self.begin = QPoint()
self.end = QPoint()
self.show()
def paintEvent(self, event):
qp = QPainter(self)
br = QBrush(QColor(100, 10, 10, 40))
qp.setBrush(br)
qp.drawRect(QRect(self.begin, self.end))
def mousePressEvent(self, event):
self.begin = event.pos()
self.end = event.pos()
# print(f"press begin {self.begin}")
# print(f"press end {self.end}")
self.update()
def mouseMoveEvent(self, event):
self.end = event.pos()
self.update()
def mouseReleaseEvent(self, event):
#self.begin = event.pos()
self.end = event.pos()
#self.update()
print(f"begin {self.begin}")
print(f"end {self.end}")
if __name__ == '__main__':
app = QApplication(sys.argv)
window = MyWidget()
window.show()
app.aboutToQuit.connect(app.deleteLater)
sys.exit(app.exec_())
Salem_Bream | 2020-12-04 19:08:15 UTC | #2
Hi, maybe it's a late response, but hopefully it will benefit someone.
I will build on your code, will try to make my code very explicit, to be easy to understand.
Next, you will find 2 code blocks:
- the code with resize working as intended.
- same as the first one, but added the visual feed back part, to make it feel professional :D .
Final Result:
PyQt6 Crash Course — a new tutorial in your Inbox every day
Beginner-focused crash course explaining the basics with hands-on examples.
-----
First Block
import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
FREE_STATE = 1
BUILDING_SQUARE = 2
BEGIN_SIDE_EDIT = 3
END_SIDE_EDIT = 4
class MyWidget(QWidget):
def __init__(self):
super().__init__()
self.setGeometry(30, 30, 600, 400)
self.begin = QPoint()
self.end = QPoint()
self.state = FREE_STATE
def paintEvent(self, event):
qp = QPainter(self)
br = QBrush(QColor(100, 10, 10, 40))
qp.setBrush(br)
qp.drawRect(QRect(self.begin, self.end))
def mousePressEvent(self, event):
if not self.begin.isNull() and not self.end.isNull():
p = event.pos()
y1, y2 = sorted([self.begin.y(), self.end.y()])
if y1 <= p.y() <= y2:
# 3 resolution, more easy to pick than 1px
if abs(self.begin.x() - p.x()) <= 3:
self.state = BEGIN_SIDE_EDIT
return
elif abs(self.end.x() - p.x()) <= 3:
self.state = END_SIDE_EDIT
return
self.state = BUILDING_SQUARE
self.begin = event.pos()
self.end = event.pos()
self.update()
def applye_event(self, event):
if self.state == BUILDING_SQUARE:
self.end = event.pos()
elif self.state == BEGIN_SIDE_EDIT:
self.begin.setX(event.x())
elif self.state == END_SIDE_EDIT:
self.end.setX(event.x())
def mouseMoveEvent(self, event):
self.applye_event(event)
self.update()
def mouseReleaseEvent(self, event):
self.applye_event(event)
self.state = FREE_STATE
if __name__ == '__main__':
app = QApplication(sys.argv)
window = MyWidget()
window.show()
app.aboutToQuit.connect(app.deleteLater)
sys.exit(app.exec_())
-----
Second Block
import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
FREE_STATE = 1
BUILDING_SQUARE = 2
BEGIN_SIDE_EDIT = 3
END_SIDE_EDIT = 4
CURSOR_ON_BEGIN_SIDE = 1
CURSOR_ON_END_SIDE = 2
class MyWidget(QWidget):
def __init__(self):
super().__init__()
self.setGeometry(30, 30, 600, 400)
self.begin = QPoint()
self.end = QPoint()
self.state = FREE_STATE
self.setMouseTracking(True)
self.free_cursor_on_side = 0
def paintEvent(self, event):
qp = QPainter(self)
br = QBrush(QColor(100, 10, 10, 40))
qp.setBrush(br)
qp.drawRect(QRect(self.begin, self.end))
if not self.free_cursor_on_side:
return
qp.setPen(QPen(Qt.black, 5, Qt.DashLine))
if self.free_cursor_on_side == CURSOR_ON_BEGIN_SIDE:
end = QPoint(self.end)
end.setX(self.begin.x())
qp.drawLine(self.begin, end)
elif self.free_cursor_on_side == CURSOR_ON_END_SIDE:
begin = QPoint(self.begin)
begin.setX(self.end.x())
qp.drawLine(self.end, begin)
def cursor_on_side(self, e_pos) -> int:
if not self.begin.isNull() and not self.end.isNull():
y1, y2 = sorted([self.begin.y(), self.end.y()])
if y1 <= e_pos.y() <= y2:
# 5 resolution, more easy to pick than 1px
if abs(self.begin.x() - e_pos.x()) <= 5:
return CURSOR_ON_BEGIN_SIDE
elif abs(self.end.x() - e_pos.x()) <= 5:
return CURSOR_ON_END_SIDE
return 0
def mousePressEvent(self, event):
side = self.cursor_on_side(event.pos())
if side == CURSOR_ON_BEGIN_SIDE:
self.state = BEGIN_SIDE_EDIT
elif side == CURSOR_ON_END_SIDE:
self.state = END_SIDE_EDIT
else:
self.state = BUILDING_SQUARE
self.begin = event.pos()
self.end = event.pos()
self.update()
def applye_event(self, event):
if self.state == BUILDING_SQUARE:
self.end = event.pos()
elif self.state == BEGIN_SIDE_EDIT:
self.begin.setX(event.x())
elif self.state == END_SIDE_EDIT:
self.end.setX(event.x())
def mouseMoveEvent(self, event):
if self.state == FREE_STATE:
self.free_cursor_on_side = self.cursor_on_side(event.pos())
if self.free_cursor_on_side:
self.setCursor(Qt.SizeHorCursor)
else:
self.unsetCursor()
self.update()
else:
self.applye_event(event)
self.update()
def mouseReleaseEvent(self, event):
self.applye_event(event)
self.state = FREE_STATE
if __name__ == '__main__':
app = QApplication(sys.argv)
window = MyWidget()
window.show()
app.aboutToQuit.connect(app.deleteLater)
sys.exit(app.exec_())
regards.
esdairim | 2020-12-04 19:08:09 UTC | #3
thank you very much for this man