标签: qgraphicsscene

QGraphicsScene 缺少特定项目更新

我有一个应用程序,您可以在其中观看给定 2D 游戏的回放:

基本上,车辆在地图上移动。视图以车辆为中心,因此地图在回放时滚动,类似于微型机器(这只是提供一个想法,实际游戏不是微型机器)。


(来源:randomracket.com

在我的场景中,当车辆四处移动时,地图是静态的。视图为重播的每一帧滚动,以便车辆居中。出于性能原因,地图在几秒内平铺QGraphicsPixmapItem

视口更新模式设置为QGraphicsView::BoundingRectViewportUpdate。项目索引方法设置为QGraphicsScene::NoIndex.

在大多数情况下,一切正常。但是当地图比平时大时,车辆不会更新。视图正在滚动,图块更新良好;但不是车辆,除非我通过放大/缩小触发完整的视口更新(因此我知道该项目已定位良好)。

车辆的 boundingRect 永远设置一次,并且是有效的(见下文,以逻辑坐标给出)。我不会在项目的边界矩形之外绘制。

调试输出的一些示例(只有第三个配置不起作用):

ok :
vehicle->boundingRect() : QRectF(-1.9391,-1.9391 3.8782x3.8782)
scene->sceneRect() : QRectF(-117.543,-38.3826 138.834x40.3217)
SCENE_CACHING : 85 tiles

ok :
vehicle->boundingRect() : QRectF(-2.88489,-2.88489 5.76979x5.76979)
scene->sceneRect() : QRectF(-68.8843,-18.2202 187.989x119.277)
SCENE_CACHING : 308 tiles

nok : vehicle won't update
vehicle->boundingRect() : QRectF(-3.45546,-3.45546 6.91092x6.91092)
scene->sceneRect() : QRectF(-64.2988,-107.802 188.927x187.445)
SCENE_CACHING : 506 tiles
Run Code Online (Sandbox Code Playgroud)

我试图调试更新通道,而油漆事件确实排除了车辆所在的区域...

任何人都知道为什么更新可能会错过特定项目?

编辑 :

Qt:4.8.1,我也看到了以前版本的问题

操作系统:Windows XP SP3,尚未在其他操作系统上测试

我没有用一个最小的例子成功地重现这个问题。最小的例子就像预期的那样工作。在现实生活中,这是所做的:

  1. 地图是从文件中读取的。它由多达数百个界定地面/天空的多边形组成(每个多边形都由多边形、边和顶点层组成)、数千张图片和纹理,然后剪裁到地面或天空,以及一些其他项目。

  2. 我计算所有剪报,然后在 …

c++ qt qgraphicsview qgraphicsscene

5
推荐指数
1
解决办法
3447
查看次数

大QImage的问题

我是C++/Qt的新手,我正在尝试用Visual Studio C++和Qt(4.8.3)创建一个应用程序.应用程序使用QGraphicsView显示图像,我需要在像素级别更改图像.

基本代码是(简化):

QImage* img = new QImage(img_width,img_height,QImage::Format_RGB32);
while(do_some_stuff) {
  img->setPixel(x,y,color);
}
QGraphicsPixmapItem* pm = new QGraphicsPixmapItem(QPixmap::fromImage(*img));
QGraphicsScene* sc = new QGraphicsScene;
sc->setSceneRect(0,0,img->width(),img->height());
sc->addItem(pm);
ui.graphicsView->setScene(sc);
Run Code Online (Sandbox Code Playgroud)

这适用于高达12000x6000像素的图像.奇怪的事情超出了这个规模.当我设置img_width=16000img_height=8000,例如,行img = new QImage(...)返回一个空的图像.图像数据应该在512,000,000字节左右,因此它不应该太大,即使在32位系统上也是如此.此外,我的机器(Win 7 64位,8 GB RAM)应该能够保存数据.

我也试过这个版本:

uchar* imgbuf = (uchar*) malloc(img_width*img_height*4);
QImage* img = new QImage(imgbuf,img_width,img_height,QImage::Format_RGB32);
Run Code Online (Sandbox Code Playgroud)

起初,这是有效的.img指针有效,并且调用img->width()例如返回正确的图像宽度(而不是0,以防图像指针为空).但是一旦我调用img->setPixel(),指针就变为null并img->width()返回0.

那么我做错了什么?或者是否有更好的方法来修改像素级别的大图像?

问候,大卫

c++ qt qpixmap qimage qgraphicsscene

5
推荐指数
1
解决办法
3233
查看次数

Qt:正确地将undo框架与QGraphicsScene集成

我正在编写一个基于QGraphicsScene画布的Qt应用程序,其上有可移动的形状,我正在尝试集成undo-redo功能.对于大多数函数,比如创建和删除形状,在它QGraphicsScene自身上实现它是相当简单的,但我希望元素是可移动的,并且运动是可撤销的.现在我正在使用场景上的橡皮筋拖曳模式ItemIsSelectableItemIsMovable项目上的标志.问题是,似乎没有好的地方来创建QUndoCommand表示形状运动.如果我在QGraphicsScene::itemChange方法中执行此操作,则选择并移动两个或更多个形状会导致不同对象的单独撤消命令被交错,因此无法合并,因此撤消会导致意外行为.QGraphicsScene当它的项目被移动时,没有任何事件被调用,我可以看到,所以我有点卡住了.

我看到的最糟糕的情况是我ItemIsMovable在自定义QGraphicsItem对象上禁用了标志并完全在QGraphicsScene鼠标事件中处理移动,但正确地重新实现该功能似乎相当复杂(我检查了Qt如何在内部执行它并且有很多代码用于处理复杂的情况,例如选择对象及其某些子对象的情况.这似乎是撤销堆栈最明显的用例(以至于撤消框架的示例程序QGraphicsScene与我的程序非常相似,除非没有多个对象移动支持)所以看起来很奇怪没有内置的方式在没有重新实现核心功能的重要部分的情况下做到这一点.有没有人有任何见解或程序的例子这样做?

c++ qt undo qgraphicsscene

5
推荐指数
1
解决办法
962
查看次数

如何制作Qt交互式文本编辑小部件

我想开发一个带有两个主要小部件的应用程序,一个是文本编辑器,另一个是图形查看器.

在此输入图像描述

基本思想是让用户将鼠标悬停在文本区域中的任何代码块上,并且选择或突出显示图形的相关部分.

对于图形小部件,经过一些研究后,似乎QGraphicsScene最符合要求,但我不确定用于文本编辑器的小部件,以便在将鼠标悬停在任何代码块上时给我一个信号(并且还发送一个块的字符串参数"id").

也需要相反的操作,因此当用户选择在图形视图中检查元素时,滚动文本视图以查看关联的代码块并突出显示它(例如在谷歌浏览器"检查元素"功能中).

qt qwidget qwebview qgraphicsscene qtextbrowser

5
推荐指数
1
解决办法
1500
查看次数

QLabel中的gif图像

我想在QLabel中添加一个添加到QGraphicsScene中的gif动画图像.我的代码在这里:

QLabel *lbl = new QLabel;
QMovie *mv = new QMovie(":/Images/sun.gif");
mv->start();
lbl->setWindowFlags(Qt::FramelessWindowHint);
lbl->setMask((new QPixmap(":/Images/sun.gif"))->mask());   // for create transparent for QLabel image
lbl->setMovie(mv);
lbl->setGeometry(10,10,10,10);
scene.addWidget(lbl);
Run Code Online (Sandbox Code Playgroud)

但是当我运行时,它将与gif的第一帧透明,当gif运行时,照片将无法完全显示,并且它将在第一帧中以透明区域运行.我怎么解决这个问题?谢谢

qt qlabel qgraphicsscene

5
推荐指数
1
解决办法
5051
查看次数

QGraphicsScene::clear 不会改变 sceneRect

我有一个 QGraphicsScene“场景”和 QGraphicsView“graphicsView”。

我有一个画图的方法。当我需要重绘所有图形时,我调用这个方法。一切都好。但我意识到 scene->clear() 不会改变 sceneRect。

我也尝试过:

graphicsView->items().clear();
scene->clear();
graphicsView->viewport()->update();
Run Code Online (Sandbox Code Playgroud)

之后,如果我通过以下方式获取 sceneRect

QRectF bound = scene->sceneRect();
qDebug() << bound.width();
qDebug() << bound.height();
Run Code Online (Sandbox Code Playgroud)

我希望bound.width和bound.height为“0”。但他们不是。我每次都会看到以前的值。当我清除场景本身时如何清除 sceneRect?

使用 GraphicsView->fitInView() 方法时,场景矩形保持不变会带来一些问题。我使用以下代码:

QRectF bounds = scene->sceneRect();
bounds.setWidth(bounds.width()*1.007);          // to give some margins
bounds.setHeight(bounds.height());              // same as above
graphicsView->fitInView(bounds);
Run Code Online (Sandbox Code Playgroud)

虽然我完全清除了场景并只添加了一个相当小的矩形,但由于 sceneRect 仍然太大,所以该矩形不适合视图。

我希望我能解释我的问题。

c++ qt qgraphicsview qgraphicsscene

5
推荐指数
1
解决办法
1723
查看次数

缩小缩小的QPixmap:无法恢复原始大小

我正在制作一个应用程序,我需要在图片上方绘制图形(即矩形)并调整整个场景的大小.我正在使用QGraphicsViewQGraphicsScene.我无法弄清楚为什么,但是当我使用时,fitIntoView()我无法在图片顶部绘制数字(它们可能是在图片后面或在边界之外绘制的).

现在我正在使用QPixmap.scaled()以使图像适合QGraphicsScene.它工作正常,除非我需要显示一个大图像,然后放大.因为我缩放图像以适应,它变得更小,当我称QGraphicsView.scale()图像缩小为小,我找不到"缩放的方法将图像恢复为原始尺寸.

在代码的缩放部分,我试图用它没有缩放的副本替换像素图,但我不能用与我的图形缩放相同的比例缩放它.任何帮助,将不胜感激!


在这里,我加载图像并缩放它

QPixmap pix;
pix = pixmap->scaled(wid, hei,Qt::KeepAspectRatio, Qt::SmoothTransformation);
scn = new QGraphicsScene(pw);
pw->setScene(scn);
p = new QGraphicsPixmapItem(pix);
p->setPixmap(pix);
scn->addItem(p);
Run Code Online (Sandbox Code Playgroud)

我画这样的数字

rect = new QGraphicsRectItem(x,y,w,h);
rect->setPen(QPen(getColor(), 1, Qt::SolidLine, Qt::FlatCap));
scn->addItem(rect);
Run Code Online (Sandbox Code Playgroud)

这是我如何缩放

pw->scale(scaleFactor_,scaleFactor_);
Run Code Online (Sandbox Code Playgroud)

更新: 现在我QWidget在顶部有一个带有工具栏的工具栏,其余的可用空间充满了自定义QGraphicsView.这是一个用于抓取鼠标事件的派生类,除了事件处理程序之外别无选择.我在我的widget的构造函数中添加了PainterGraphicsView:

pw = new PainterGraphicsView();
ui->gridLayout_3->addWidget(pw);
Run Code Online (Sandbox Code Playgroud)

我每次加载新图像时都会重新创建场景:

scn = new QGraphicsScene(pw);
pw->setScene(scn);
QRect r = QRect(0,0, pw->width()-5, pw->height()-5);
scn->setSceneRect(r);
Run Code Online (Sandbox Code Playgroud)

加载图像后,我可以在其上绘制图形,它看起来像这样:

在此输入图像描述

缩放内容如下所示:

在此输入图像描述

正如您所看到的,数字与像素图一起缩放,这正是我需要它工作的方式.我唯一需要解决的是缩放像素图的低质量.正如我已经说过的,我尝试用我的ZoomIn方法中的原始像素替换像素图,但我无法保存数字的位置.

void DrawerWidget::on_btZoom_clicked()
{
    p->setPixmap(pix); //p is QGraphicsPixmapItem, …
Run Code Online (Sandbox Code Playgroud)

qt qpixmap qgraphicsview qgraphicsscene

5
推荐指数
1
解决办法
1135
查看次数

强制 QGraphicsItem 使用 z 值并忽略父子关系

我在使用QGraphicsItem类时遇到问题。

有一个 base_parent、base_part、part_1、part_2。base_parent 是 base_part 的父级。part_1 和 part_2 是 base_part 的子代。我想要做的是以part_1和part_2堆叠在base_parent后面和base_part堆叠在base_parent前面的方式设置这些项目的Z值。所以我实现的是这样的:

  base_part->setParentItem(base_parent);
  part_1->setParentItem(base_part);
  part_2->setParentItem(base_part);
Run Code Online (Sandbox Code Playgroud)

起初尝试使用 setZValue() 设置 z 值,但显然它不起作用。

base_parent->setZValue(0);
base_part->setZValue(1);
part_1->setZValue(-1);
part_2->setZValue(-2);
Run Code Online (Sandbox Code Playgroud)

文档中说:

项目的子项堆叠在父项的顶部

我放弃了,但后来我看到了另一个参数。

您可以在项目上调用 setZValue() 以将其显式堆叠在其他同级项目的顶部或下方。项目的默认 Z 值为 0。具有相同 Z 值的项目按插入顺序堆叠。

您可以调用 stackBefore() 对子项列表重新排序。这将直接修改插入顺序。

您可以设置 ItemStacksBehindParent 标志以将子项堆叠在其父项后面。

所以我尝试设置ItemStacksBehindParent标志,但它移动了整个孩子后面的堆叠,这意味着 base_part、part_1 和 part_2 被堆叠在 base_parent 后面。

后来我发现了另一个标志,ItemNegativeZStacksBehindParent.

如果 z 值为负,该项目会自动堆叠在其父项后面。此标志使 setZValue() 能够切换 ItemStacksBehindParent。这个标志是在 Qt 4.6 中引入的。

所以我又试了一次:

  base_part->setFlag(QGraphicsItem::ItemNegativeZStacksBehindParent);
  part_1->setFlag(QGraphicsItem::ItemNegativeZStacksBehindParent);
  part_2->setFlag(QGraphicsItem::ItemNegativeZStacksBehindParent);
Run Code Online (Sandbox Code Playgroud)

使用此标志将 part_1 和 part_2 堆叠在 base_part 后面,但它们仍然堆叠在 base_parent 前面。

我想知道是否有办法强制项目仅使用 Z …

c++ qt qgraphicsview qgraphicsitem qgraphicsscene

5
推荐指数
1
解决办法
1188
查看次数

QGraphicsView:如何使橡皮筋选择仅出现在鼠标左键上?

我想制作一个QGraphicsScene并在 中显示它QGraphicsView。我想通过鼠标中键滚动场景并通过左键进行橡皮筋选择。但我不知道如何使橡皮筋选择仅通过鼠标左键出现。

这是我的代码:

# -*- coding: utf-8 -*-

import os, sys

from PyQt5 import QtWidgets, QtCore, QtGui, QtSvg

class MegaSceneView(QtWidgets.QGraphicsView):
    def __init__(self, parent=None):
        super(MegaSceneView, self).__init__(parent)
        self._scale_factor = 1.0

        self._scale_by = 1.2
        self.setAcceptDrops(True)

        self.setRenderHint(QtGui.QPainter.Antialiasing)
        self.setMouseTracking(True)
        self.setRubberBandSelectionMode(QtCore.Qt.IntersectsItemShape)
        self.setDragMode(QtWidgets.QGraphicsView.RubberBandDrag)

        self._prev_mouse_scene_pos = None


    def mousePressEvent(self, event):
        if (event.buttons() & QtCore.Qt.MidButton) != QtCore.Qt.NoButton:
            self._prev_mouse_scene_pos = (event.pos())
        super(MegaSceneView, self).mousePressEvent(event)

    def mouseReleaseEvent(self, event):
        super(MegaSceneView, self).mouseReleaseEvent(event)
        self._prev_mouse_scene_pos = None

    def mouseMoveEvent(self, event):
        super(MegaSceneView, self).mouseMoveEvent(event)

        if (event.buttons() & QtCore.Qt.MidButton) != QtCore.Qt.NoButton:
            cur_mouse_pos = (event.pos())
            if …
Run Code Online (Sandbox Code Playgroud)

qt pyqt qgraphicsview qgraphicsscene qt5

5
推荐指数
2
解决办法
2201
查看次数

PyQt:如何在QGraphicsView中设置滚动条和显示区域大小策略

我正在尝试创建一个简单的图形用户界面来显示设备某些组件的(内存)布局,但我很难在显示区域执行我想要的策略。
首先让我展示一下到目前为止我所拥有的内容(我的代码变得相当大,但我将代码更改/缩小到任何人都能够运行它所需的最低限度):

#!/usr/local/bin/python3
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
import sys

class Register(QGraphicsRectItem):

    RegisterSize = 125

    NameColor = QColor(Qt.blue)
    ValueColor = QColor(0, 154, 205)

    def __init__(self, name, value, pos, parent = None):
        super(Register, self).__init__(parent)
        self.setPos(pos)

        self.width = Register.RegisterSize
        self.height = 0

        self.set_register_name(name)
        self.set_register_value(value)

        self.setRect(0, 0, self.width, self.height)

    def set_register_name(self, name):
        self.text_item = QGraphicsTextItem(name, self)
        self.text_item.setDefaultTextColor(Register.NameColor)
        self.height += self.text_item.boundingRect().height()

    def set_register_value(self, value):
        self.value_item = QGraphicsTextItem(str(value), self)
        self.value_item.setDefaultTextColor(Register.ValueColor)
        self.value_item.setPos(self.text_item.boundingRect().bottomLeft())
        self.height += self.value_item.boundingRect().height()

class Title(QGraphicsTextItem):

    TitleFont = …
Run Code Online (Sandbox Code Playgroud)

python pyqt qgraphicsview qgraphicsscene

5
推荐指数
1
解决办法
4293
查看次数