如何将AVIOD橡胶带成为AA线,以及如何设置橡胶带仅显示边界线?
我编写一个简单的应用,而拖动或缩放mainview
,partView
橡皮筋将在partview
中显示场景区域。成为一条线,有时橡胶带消失了。那么如何出现这种现象?有时我希望橡皮筋只显示其边框线,不包含它的浅蓝色矩形,那么我该如何编写代码?
我的代码
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
import random
import math
r = lambda : random.randint(0, 255)
r255 = lambda : (r(), r(), r())
class Scene(QGraphicsScene):
def __init__(self):
super().__init__()
for i in range(1000):
item = QGraphicsEllipseItem()
item.setRect(0, 0, r(), r())
item.setBrush(QColor(*r255()))
item.setPos(r()*100, r()*100)
self.addItem(item)
class MainView(QGraphicsView):
sigExposeRect = pyqtSignal(QRectF)
def drawBackground(self, painter: QPainter, rect: QRectF) -> None:
super().drawBackground(painter, rect)
self.sigExposeRect.emit(rect)
def wheelEvent(self, event: QWheelEvent) -> None:
factor = math.pow(2.7, event.angleDelta().y()/360)
self.scale(factor, factor)
class PartView(QGraphicsView):
def __init__(self):
super().__init__()
self.r = QRubberBand(QRubberBand.Rectangle, self)
self.r.setWindowOpacity(1)
self.r.show()
class View(QSplitter):
def __init__(self):
super().__init__()
self.m = MainView()
self.m.setMouseTracking(True)
self.m.setDragMode(QGraphicsView.ScrollHandDrag)
self.m.sigExposeRect.connect(self.onExposeRect)
self.p = PartView()
self.m.setScene(Scene())
self.p.setScene(self.m.scene())
self.p.fitInView(self.m.scene().itemsBoundingRect())
self.addWidget(self.m)
self.addWidget(self.p)
def onExposeRect(self, rect: QRectF):
prect = self.p.mapFromScene(rect).boundingRect()
self.p.r.setGeometry(prect)
app = QApplication([])
v = View()
v.show()
app.exec()
I write a simple app, While drag or scale the MainView
, The PartView
rubberband will show scene area in PartView
.But sometime the rubber-band become a line, and sometime the rubberband disappear.So How to aviod this phenomenon appear?And sometime I want the rubberband only show it's border-line, not contain it's light-blue rectangle,So how can I write code ?
My Code
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
import random
import math
r = lambda : random.randint(0, 255)
r255 = lambda : (r(), r(), r())
class Scene(QGraphicsScene):
def __init__(self):
super().__init__()
for i in range(1000):
item = QGraphicsEllipseItem()
item.setRect(0, 0, r(), r())
item.setBrush(QColor(*r255()))
item.setPos(r()*100, r()*100)
self.addItem(item)
class MainView(QGraphicsView):
sigExposeRect = pyqtSignal(QRectF)
def drawBackground(self, painter: QPainter, rect: QRectF) -> None:
super().drawBackground(painter, rect)
self.sigExposeRect.emit(rect)
def wheelEvent(self, event: QWheelEvent) -> None:
factor = math.pow(2.7, event.angleDelta().y()/360)
self.scale(factor, factor)
class PartView(QGraphicsView):
def __init__(self):
super().__init__()
self.r = QRubberBand(QRubberBand.Rectangle, self)
self.r.setWindowOpacity(1)
self.r.show()
class View(QSplitter):
def __init__(self):
super().__init__()
self.m = MainView()
self.m.setMouseTracking(True)
self.m.setDragMode(QGraphicsView.ScrollHandDrag)
self.m.sigExposeRect.connect(self.onExposeRect)
self.p = PartView()
self.m.setScene(Scene())
self.p.setScene(self.m.scene())
self.p.fitInView(self.m.scene().itemsBoundingRect())
self.addWidget(self.m)
self.addWidget(self.p)
def onExposeRect(self, rect: QRectF):
prect = self.p.mapFromScene(rect).boundingRect()
self.p.r.setGeometry(prect)
app = QApplication([])
v = View()
v.show()
app.exec()
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我认为问题在于,
QRECT
传递给缩写
方法仅包括以前在视口中没有的背景部分。不过对此并不积极。无论哪种方式,我都可以通过将整个视口区域的区域发送到
OnexPosErect
插槽来实现您仅避免绘制橡皮筋的一部分的目标。I think the problem is that the
qrect
passed to thedrawBackground
method is only includes the portion of the background that wasn't previously in the viewport. Not positive about that though.Either way I was able to achieve your goal of avoiding only a section of the rubber band being drawn, by sending the area for the entire viewport to the
onExposeRect
slot.关于图形视图的一个基本方面是它在绘制数千个要素方面的高性能。
为此,最重要的优化之一就是仅更新真正需要重新绘制的场景部分,类似于项目视图所做的,因为它们通常仅重新绘制 实际需要更新的项目,而是总是绘画整个可见区域,这可能是一个巨大的瓶颈。
这就是重新覆盖
缩写
无效的原因:有时,仅更新场景的一小部分(在某些情况下,甚至完成了 no 更新),以及rect
缺陷>的参数
仅包括 部分,而不是整个可见区域。结果是,在这种情况下,信号将散发出与可见区域不一致的矩形。由于可见区域是相对于滚动区域的 viewport ,因此接收有关该区域更新的唯一安全方法是连接到水平和垂直滚动条(即使隐藏了它们,它们即使它们始终可以工作)。
进一步的预防措施是确保每当更改场景rect时,也可以更新可见的矩形(因为滚动条可能不会反映这种更改),通过连接到
saceerectChanged
信号,也覆盖setScenerect()
。考虑到垂直和滚动条的变化可能是重合的,通常是一个好主意,最好用0-延迟QTimer延迟信号,以便仅当对可见区域发生更多更改时仅发送一次。请注意,由于您实际上并未使用Qrubberband的功能,因此其使用情况几乎没有用,尤其是在您还需要自定义绘画的情况下。另外,由于橡皮筋是视野的孩子,即使滚动了预览视图,它也将始终保持其位置。
在下面的示例中,我将显示绘制“假”橡皮筋的两种方法(但仅选择其中一个,即评论一个或另一个来测试它们),这始终与源和目标视图都一致。
ps:当它们真正有意义时,请使用单个字母变量(常见变量,坐标,循环占位符等),而不是用于复杂对象,尤其是属性:使用
self.m < /code>或
self.p
,您获得的唯一结果是使代码对您和其他人的可读性降低。A fundamental aspect about Graphics View is its high performance in drawing even thousands of elements.
To achieve this, one of the most important optimization is updating only the portions of the scene that really need redrawing, similar to what item views do, as they normally only redraw the items that actually require updates, instead of always painting the whole visible area, which can be a huge bottleneck.
This is the reason for which overriding
drawBackground
is ineffective: sometimes, only a small portion of the scene is updated (and, in certain situations, even no update is done at all), and therect
argument ofdrawBackground
only includes that portion, not the whole visible area. The result is that in these situations, the signal will emit a rectangle that will not be consistent with the visible area.Since the visible area is relative to the viewport of the scroll area, the only safe way to receive updates about that area is to connect to the horizontal and vertical scroll bars (which always work even if they are hidden).
A further precaution is to ensure that the visible rectangle is also updated whenever the scene rect is changed (since that change might not be reflected by the scroll bars), by connecting to the
sceneRectChanged
signal and also overriding thesetSceneRect()
of the source view. Considering that the changes in vertical and scroll bars might coincide, it's usually a good idea to delay the signal with a 0-delay QTimer, so that it's only sent once when more changes to the visible area happen at the same time.Note that since you're not actually using the features of QRubberBand, there's little use in its usage, especially if you also need custom painting. Also, since the rubber band is a child of the view, it will always keep its position even if the preview view is scrolled.
In the following example I'll show two ways of drawing the "fake" rubber band (but choose only one of them, either comment one or the other to test them) that will always be consistent with both the source and target views.
PS: please use single letter variables when they actually make sense (common variables, coordinates, loop placeholders, etc.), not for complex objects, and especially for attributes: there's no benefit in using
self.m
orself.p
, and the only result you get is to make code less readable to you and others.