- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在使用 QGraphicsSvgItem
子类,它从文件中读取一些内容,将内容放入 QDomDocument
中,进行一些初始处理,然后将处理后的 DOM 设置到渲染器上.
在程序处理过程中,需要对一份预处理后的DOM进行额外的改动,所以DOM存放在类中。更改后,DOM 放置在渲染器上。
class MyGraphicsSvgItem : public QGraphicsSvgItem
{
public:
MyGraphicsSvgItem (QGraphicsItem *parent = 0):
QGraphicsSvgItem(parent),
_svgXML() {}
~MyGraphicsSvgItem () { delete renderer(); }
void CheckAndChangeSomeThings() {}
void LoadStuff (QString fileName)
{
QFile file(fileName);
file.open(QFile::ReadOnly | QFile::Text);
QTextStream in(&file);
QString svgContent = in.readAll();
file.close();
_svgXML.setContent(svgContent);
CheckAndChangeSomeThings(); // this modifies _svgXML
QByteArray _data = _svgXML.toByteArray();
setSharedRenderer(new QSvgRenderer(_data)); // very slow
}
void ChangeThingslater();
void ChangeSomeThingslater()
{
ChangeThingslater(); // this modifies _svgXML
renderer()->load(_svgXML.toByteArray()); // very slow - no file involved
}
protected:
QDomDocument _svgXML;
};
在将 DOM 分配给渲染器的那几行中,处理速度似乎很慢。
QByteArray _data = _svgXML.toByteArray();
setSharedRenderer(new QSvgRenderer(_data));
如果我跳过 DOM 处理 - 如果我将渲染器设置为文件 - 代码速度会大大加快:
保留所有代码,但替换
setSharedRenderer(new QSvgRenderer(_data)); // VERY SLOW
与
setSharedRenderer(new QSvgRenderer(fileName)); // FAST
所以瓶颈似乎是从 QByteArray
加载 svg 渲染器。
我在寻找替代品......文档中没有提到性能
QSvgRenderer::QSvgRenderer(const QString & filename, QObject * parent = 0)
Constructs a new renderer with the given parent and loads the contents of the SVG file with the specified filename.QSvgRenderer::QSvgRenderer(const QByteArray & contents, QObject * parent = 0)
Constructs a new renderer with the given parent and loads the SVG data from the byte array specified by contents.QSvgRenderer::QSvgRenderer(QXmlStreamReader * contents, QObject * parent = 0)
Constructs a new renderer with the given parent and loads the SVG data using the stream reader specified by contents.
正在寻找QXmlStreamReader Class ,我发现它的构造函数是相似的!此外,它说
In some cases it might also be a faster and more convenient alternative for use in applications that would otherwise use a DOM tree
我似乎在兜圈子,尽管 DOM 中已经有一个格式良好的 xml,但我似乎无法利用它!
我的替代方案是什么,是从预处理的 DOM 加载渲染器,还是使用其他方式预处理 xml - 使用渲染器可以快速读取的 DOM 以外的东西?
qt 4.8。语言
最佳答案
您可以使用 QtConcurrent::run
在线程队列上执行的辅助方法中执行所有 DOM 处理。
您可以直接在项目中使用QSvgRenderer
。在 worker 方法中初始化它,并从 QByteArray
而不是文件加载。然后,您可以将渲染器传递给 GUI 线程,并通过在 QGraphicsSvgItem
上设置它来使用它来渲染图形项。
注意事项:
由于您在工作线程中创建渲染器,因此在工作线程中使用完渲染器后必须将其移至空线程。相反,一旦 GUI 线程接收到它,就必须将其移动到 GUI 线程。
回想一下,moveToThread
只能从对象的当前线程或任何 thread() == 0
的线程调用。
在 Qt 4.8 中,QGraphicsSvgItem::setSharedRenderer
中有一个错误:它没有正确地将渲染器的 repaintNeeded
信号连接到它的 update
方法。解决此问题的方法是将信号手动连接到您自己的更新插槽。
这将防止 GUI 被长时间处理阻塞。
像您一样从项目内部重新进入事件循环是错误的来源,从设计的角度来看这只是一个非常糟糕的主意。请改用文件对话框的非阻塞 API。
下面是一个演示此技术的示例。当加载/处理项目时,它还会显示一个小的微调器。为此目的有一个模拟延迟。
#include <QGraphicsView>
#include <QGraphicsSvgItem>
#include <QGraphicsSceneMouseEvent>
#include <QFileDialog>
#include <QSvgRenderer>
#include <QDomDocument>
#include <QtConcurrentRun>
#include <QFutureWatcher>
#include <QThread>
#include <QApplication>
struct Thread : public QThread { using QThread::sleep; }; // Needed for Qt 4 only
class RendererGenerator {
QString m_fileName;
void process(QDomDocument &) {
Thread::sleep(3); /* let's pretend we process the DOM for a long time here */
}
QByteArray generate(const QByteArray & data) {
QDomDocument dom;
dom.setContent(data);
process(dom);
return dom.toByteArray();
}
public:
typedef QSvgRenderer * result_type;
RendererGenerator(const QString & fileName) : m_fileName(fileName) {}
QSvgRenderer * operator()() {
QFile file(m_fileName);
if (file.open(QIODevice::ReadOnly)) {
QByteArray data = file.readAll();
QScopedPointer<QSvgRenderer> renderer(new QSvgRenderer);
renderer->load(generate(data));
renderer->moveToThread(0);
return renderer.take();
}
return 0;
}
};
class UserSvgItem : public QGraphicsSvgItem {
Q_OBJECT
QSvgRenderer m_spinRenderer, * m_lastRenderer;
QScopedPointer<QSvgRenderer> m_renderer;
QFuture<QSvgRenderer*> m_future;
QFutureWatcher<QSvgRenderer*> m_watcher;
QGraphicsView * aView() const {
QList<QGraphicsView*> views = scene()->views();
return views.isEmpty() ? 0 : views.first();
}
Q_SLOT void update() { QGraphicsSvgItem::update(); }
void mousePressEvent(QGraphicsSceneMouseEvent * event) {
if (event->button() == Qt::LeftButton) askForFile();
}
void setRenderer(QSvgRenderer * renderer) {
if (m_lastRenderer) disconnect(m_lastRenderer, SIGNAL(repaintNeeded()), this, SLOT(update()));
setSharedRenderer(renderer);
m_lastRenderer = renderer;
connect(renderer, SIGNAL(repaintNeeded()), SLOT(update()));
if (aView()) aView()->centerOn(this);
}
void askForFile() {
QFileDialog * dialog = new QFileDialog(aView());
connect(dialog, SIGNAL(fileSelected(QString)), SLOT(loadFile(QString)));
dialog->setAcceptMode(QFileDialog::AcceptOpen);
dialog->setAttribute(Qt::WA_DeleteOnClose);
dialog->show();
}
Q_SLOT void loadFile(const QString & file) {
if (m_future.isRunning()) return;
setRenderer(&m_spinRenderer);
m_future = QtConcurrent::run(RendererGenerator(file));
m_watcher.setFuture(m_future);
}
Q_SLOT void rendererReady() {
m_renderer.reset(m_future.result());
m_renderer->moveToThread(thread());
setRenderer(m_renderer.data());
}
public:
UserSvgItem(const QString & fileName = QString(), QGraphicsItem *parent = 0) :
QGraphicsSvgItem(fileName, parent), m_lastRenderer(0) {
connect(&m_watcher, SIGNAL(finished()), SLOT(rendererReady()));
setFlags(QGraphicsItem::ItemClipsToShape);
setCacheMode(QGraphicsItem::NoCache);
}
void setWaitAnimation(const QByteArray & data) { m_spinRenderer.load(data); }
};
namespace {
const char svgCircle[] =
"<svg height=\"100\" width=\"100\"><circle cx=\"50\" cy=\"50\" r=\"40\" stroke=\"black\" stroke-width=\"3\" fill=\"red\" /></svg>";
const char svgRectangle[] =
"<svg width=\"400\" height=\"110\"><rect width=\"300\" height=\"100\" style=\"fill:rgb(0,0,255);stroke-width:3;stroke:rgb(0,0,0)\"></svg>";
const char svgThrobber[] =
"<svg width=\"16\" height=\"16\" viewBox=\"0 0 300 300\" xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\"><path d=\"M 150,0 a 150,150 0 0,1 106.066,256.066 l -35.355,-35.355 a -100,-100 0 0,0 -70.711,-170.711 z\" fill=\"#3d7fe6\"><animateTransform attributeName=\"transform\" attributeType=\"XML\" type=\"rotate\" from=\"0 150 150\" to=\"360 150 150\" begin=\"0s\" dur=\"1s\" fill=\"freeze\" repeatCount=\"indefinite\" /></path></svg>";
void write(const char * str, const QString & fileName) {
QFile out(fileName);
if (out.open(QIODevice::WriteOnly | QIODevice::Truncate)) out.write(str);
}
}
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
write(svgRectangle, "rectangle.svg"); // Put svg resources into the working directory
write(svgCircle, "circle.svg");
QGraphicsScene scene;
UserSvgItem item("circle.svg");
QGraphicsView view(&scene);
scene.addItem(&item);
item.setWaitAnimation(QByteArray::fromRawData(svgThrobber, sizeof(svgThrobber)-1));
view.show();
return app.exec();
}
#include "main.moc"
关于c++ - 在预处理的 svg xml 文档上设置 QGraphicsSvgItem 渲染器非常慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30983142/
关闭。这个问题不满足Stack Overflow guidelines .它目前不接受答案。 想改善这个问题吗?更新问题,使其成为 on-topic对于堆栈溢出。 7年前关闭。 Improve thi
有两个 SVG 元素( SVG1 和 SVG2 ),其中 SVG1 是一个包含各种元素的大区域,会不时添加、删除和重新定位。另一方面,SVG2 需要用作 图标化表示(小) SVG1 的版本,非常小,但
我知道我们可以使用 document.createElementNS("http://www.w3.org/2000/svg","line"); 创建一个嵌入到html页面。 但是,这种方法似乎不适用
我正在尝试使用 Flutter SVG 依赖项,我将 svg 放入 Assets 中,在 pubspec.yaml 中设置,并在我的小部件中设置,但是,使用黑色容器加载 svg 我已经尝试过更改 sv
为什么这样的演示:http://jsbin.com/ejorus/2/edit,将元素嵌套在另一个元素内? JS
很难说出这里问的是什么。这个问题是含糊的、模糊的、不完整的、过于宽泛的或修辞性的,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开它,visit the help center 。 已关
我正在尝试在 SVG 中做一些非常简单的事情: 将整个视口(viewport)分成两个矩形 每个矩形的宽度应为视口(viewport)宽度的 50% 每个矩形的高度应为视口(viewport)高度的
我试图将 play svg 居中放置在 SVG 圆圈的中间,但似乎不知道该怎么做。 垂直和水平。 https://jsfiddle.net/c0qshm0t/17/ 最
是否可以使用一个 SVG 形状作为另一个形状的填充? 最佳答案 您想使用 SVG Pattern .见 this example : 注意
我在 SVG 中有一个非常简单的路径。 (预览:https://i.imgur.com/nVnxcRg.png) 我想要
我可以通过以下方式创建多边形: #!/usr/bin/env python from shapely.geometry import Polygon area = Polygon(((52, 13),
我使用 require 的 SVG 没有显示。 在我的终端中,svg Assets 被发出并且路径在我的 html 中正确设置。 但是,SVG 不会显示,而其他格式(如 jpg 或 png)可以显示
我在 SVG 混合模式中遇到了问题。我在 SVG 中有四个路径,我想用公式组合它们:(1*2) + (3*4),即路径 1 和路径 2 应该使用乘法模式混合,类似地路径 3 和路径 4 应该使用混合相
我无法超过 2 个级别。 (在 Iceweasel 和 Chromium 上尝试过。) 作为测试,我尝试了 this earlier reply 中提供的代码的变体。 .这个由 3 个单独的文件组成,
请引用以下组中的clip-path 组 ID -> “container_svg_symbolGroup1_0(即圆圈符号)在我删除图表中可见的剪辑路径时不可见。 问题是什么?为什么
使用联合 js 在 svg 中创建了一个文本区域。但是,我无法在文本区域中输入任何文本。如何使文本区域可编辑? 代码: var graph = new joint.dia.Graph;
您可以不受限制地停止和重复动画,但如果您重新启动一个不确定的动画,它将失去其累积值并从初始值开始。 也许我应该用一个例子来澄清;拿这个动画: 如果我停止此动画,并开始影响同一对象旋转的不同动画(
如果我在浏览器中显示常规 SVG(作为独立文件或嵌入在 HTML 中),在拥有大量单独的路径元素和一个巨大的路径元素之间在效率上是否有任何理论上的差异? 我正在考虑将某种动画从一张图片变成一张完全不同
logo的turtlegraphics的svg路径中是否有等价物? 而不是硬编码的 x 和 y 坐标,这也迫使我在移动更相对的“增量”方法时调整控制点。 我的解决方案应该适用于 FOCS(Firefo
目前正在使用 SVG 元素与一堆 元素将使它具有一种逐渐变细的边缘。我尝试了很多不同的 CSS 样式来解决这个问题,但没有任何效果。这是一个带有针迹的圆圈的代码:
我是一名优秀的程序员,十分优秀!