Qt GraphicsScene XOR Line 或 Line 在单独的层中?

Posted

技术标签:

【中文标题】Qt GraphicsScene XOR Line 或 Line 在单独的层中?【英文标题】:Qt GraphicsScene XOR Line or Line in separate layer? 【发布时间】:2017-04-17 21:10:05 【问题描述】:

我已经开始学习 Qt,并尝试提高我的基本 C++ 技能。 在 GraphicsScene 中,我尝试使用鼠标(鼠标事件)绘制一条线。 当我开始在 GraphicsScene 中绘制一条线时,会从原点绘制一条细虚线,在该原点我首先单击到当前鼠标位置并随鼠标移动,然后单击第二个点。为了抹去它,我把它画成黑色。如果我将鼠标悬停在已经画出的线条上,你会在它们上面看到黑色的画线。要在不留下标记的情况下取消绘制,GraphicsScene 上的 XOR 操作会派上用场,或者如果我可以在不同的层中绘制而不接触另一层可能会很方便。但我还不知道该怎么做。该示例位于https://github.com/JackBerkhout/QT_Draw001 在 line.cpp 中是函数 setLineP2(int x, int y),它绘制和擦除那条细虚线。 请问有人可以帮我吗?

【问题讨论】:

你能不能给我解释一下 嗨,由于消息长度的限制,我需要将其拆分为多个 cmets。假设我已经画了一条粗紫色线(第一条)。然后我开始画第二条线,我们先点击起点。不如拖动鼠标。我们看到一条细的白色虚线,其端点跟随鼠标。 所以我把它画成白色。然后为了更新它的位置,我首先取消绘制它(仅使用背景颜色),然后使用白色再次在新位置上绘制它。当我将线拖到第一个上面时,我们可以看到我们在那个上面画了很多黑线。最后,当我点击端点时,会画出紫色的粗线。黑线标记在第一行上仍然可见,这是我们在第一次单击后移动鼠标时越过的。 如果我们可以在线路构建阶段使用第二层,我们就不会在第一层出现(黑色)标记。或者,如果我们使用 XOR 笔模式,它会通过在同一位置第二次绘制来再次重建底层颜色。我希望这能更好地解释它。在Windows上的VS中,这很简单,但是我使用Linux,而在QT中则不简单,因为它似乎缺乏图形场景中的异或功能。 我已经修改了你的代码,看看是不是你想要的:github.com/eyllanesc/***/tree/master/GraphicsScene 【参考方案1】:

主要的误解是将QGraphicsScene 视为某种位图:它不是!它是可以呈现自身的项目的集合,以及它们的空间索引。在场景中,如果您希望删除/隐藏某些内容,您不能对其进行过度绘制 - 只需根据需要删除/隐藏相关项目即可。场景将处理所有细节 - 这就是它的用途

此时您必须忘记 GDI-anything。您不是在此处的原始 DC 上绘画。即使在使用原始 GDI 时,您也不想在窗口的 DC 上绘画,因为它会闪烁,您应该在位图上绘画并将位图 blit 到窗口。

例如,您的 eraseScene 方法在场景顶部添加了一个矩形,由于保留了所有先前的项目(您可以遍历它们),因此浪费了内存和资源,而它应该做的只是 clear场景(或其等价物):

void MainWindow::eraseScreen(void)

    [...]
    scene->addRect(0, 0, width()+1000, height()+1000, pen, brush);

对比正确的:

void MainWindow::eraseScreen(void)

    scene->clear();

下面是一个完整的示例,它近似于您在代码中可能要执行的操作。 它有 120 行长。有点难以弄清楚你到底要做什么,因为你的代码非常复杂 - 在问题中用简单的术语描述确切的行为很有用。

该示例使用QPainterPath 来保存QPainterPathItem 呈现的MoveToLineTo 元素列表。它还使用QGraphicsLineItem 来显示瞬态线。

MyScene::PathUpdater 用于包含修改路径的上下文,并确保维护适当的前置条件和后置条件。即:

    由于QPainterPath 是隐式共享的,您应该清除QGraphicsPathItem 持有的路径以避免不必要的隐式复制。这是修改m_path之前的必要前提。

    m_path 修改后,必须更新路径项,并发出新状态。

以下其他点值得注意:

    按值保存成员会导致显着缺少任何内存管理代码(!) - 编译器为我们完成了这一切。你不会在任何地方找到一个newdelete。它们不是必需的,而且我们不会因为不手动执行此操作而支付额外费用。现代 C++ 应该是这个样子。

    显示MainWindowMyScene 之间的明显区别。 MainWindowMyScene 的细节一无所知,反之亦然。 main 中的代码充当两者之间的适配器。

    利用 C++11。

    SO 测试用例和示例所需的简洁风格:为了学习,最好将它们全部保存在一个文件中,以便轻松查看代码的所有部分。它只有 120 行,而如果跨文件拆分则超过两倍。我们的大脑利用参考的位置。拆分代码会让你更难理解。

另见

    Another demo of interactive item creation。 A more advanced example of status notifications。

// https://github.com/KubaO/***n/tree/master/questions/scene-polygon-7727656
#include <QtWidgets>

class MainWindow : public QWidget

   Q_OBJECT
   QGridLayout m_layoutthis;
   QPushButton m_new"New";
   QPushButton m_erase"Erase All";
   QLabel m_label;
   QGraphicsView m_view;
public:
   MainWindow() 
      m_layout.addWidget(&m_new, 0, 0);
      m_layout.addWidget(&m_erase, 0, 1);
      m_layout.addWidget(&m_label, 0, 2);
      m_layout.addWidget(&m_view, 1, 0, 1, 3);
      m_view.setBackgroundBrush(Qt::black);
      m_view.setAlignment(Qt::AlignBottom | Qt::AlignLeft);
      m_view.scale(1, -1);
      connect(&m_new, &QPushButton::clicked, this, &MainWindow::newItem);
      connect(&m_erase, &QPushButton::clicked, this, &MainWindow::clearScene);
   
   void setScene(QGraphicsScene * scene) 
      m_view.setScene(scene);
   
   Q_SIGNAL void newItem();
   Q_SIGNAL void clearScene();
   Q_SLOT void setText(const QString & text)  m_label.setText(text); 
;

class MyScene : public QGraphicsScene 
   Q_OBJECT
public:
   struct Status 
      int paths;
      int elements;
   ;
private:
   bool m_newItem = ;
   Status m_status = 0, 0;
   QPainterPath m_path;
   QGraphicsPathItem m_pathItem;
   QGraphicsLineItem m_lineItem;
   struct PathUpdater 
      Q_DISABLE_COPY(PathUpdater)
      MyScene & s;
      PathUpdater(MyScene & scene) : s(scene) 
         s.m_pathItem.setPath(); // avoid a copy-on-write
      
      ~PathUpdater() 
         s.m_pathItem.setPath(s.m_path);
         s.m_status = 0, s.m_path.elementCount();
         for (auto i = 0; i < s.m_status.elements; ++i) 
            auto element = s.m_path.elementAt(i);
            if (element.type == QPainterPath::MoveToElement)
               s.m_status.paths++;
         
         emit s.statusChanged(s.m_status);
      
   ;
   void mousePressEvent(QGraphicsSceneMouseEvent *event) override 
      PathUpdater updater(*this);
      auto pos = event->scenePos();
      m_lineItem.setLine(0, 0, pos.x(), pos.y());
      m_lineItem.setVisible(true);
      if (m_path.elementCount() == 0 || m_newItem)
         m_path.moveTo(pos);
      m_path.lineTo(pos.x()+1,pos.y()+1); // otherwise lineTo is a NOP
      m_newItem = ;
   
   void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override 
      PathUpdater updater(*this);
      auto pos = event->scenePos();
      m_lineItem.setLine(0, 0, pos.x(), pos.y());
      m_path.setElementPositionAt(m_path.elementCount()-1, pos.x(), pos.y());
   
   void mouseReleaseEvent(QGraphicsSceneMouseEvent *) override 
      m_lineItem.setVisible(false);
   
public:
   MyScene() 
      addItem(&m_pathItem);
      addItem(&m_lineItem);
      m_pathItem.setPen(Qt::red);
      m_pathItem.setBrush(Qt::NoBrush);
      m_lineItem.setPen(Qt::white);
      m_lineItem.setVisible(false);
   
   Q_SLOT void clear() 
      PathUpdater updater(*this);
      m_path = ;
   
   Q_SLOT void newItem() 
      m_newItem = true;
   
   Q_SIGNAL void statusChanged(const MyScene::Status &);
   Status status() const  return m_status; 
;

int main(int argc, char *argv[])

   using Q = QObject;
   QApplication appargc, argv;
   MainWindow w;
   MyScene scene;
   w.setMinimumSize(600, 600);
   w.setScene(&scene);
   Q::connect(&w, &MainWindow::clearScene, &scene, &MyScene::clear);
   Q::connect(&w, &MainWindow::newItem, &scene, &MyScene::newItem);
   auto onStatus = [&](const MyScene::Status & s)
      w.setText(QStringLiteral("Paths: %1 Elements: %2").arg(s.paths).arg(s.elements));
   ;
   Q::connect(&scene, &MyScene::statusChanged, onStatus);
   onStatus(scene.status());
   w.show();
   return app.exec();

#include "main.moc"

【讨论】:

@JackBerkhout 查看编辑。我在上面提供的 Qt 示例比使用原始 Borland C++ 及其图形库所做的任何事情都简单得多。 嗨库巴,非常感谢!现在我明白了那部分。我首先在 Udemy.com 上注册了一些 C++ 和 QT 课程……要学习的东西很多。

以上是关于Qt GraphicsScene XOR Line 或 Line 在单独的层中?的主要内容,如果未能解决你的问题,请参考以下文章

Pyqt5 Graphicsscene大小和位置

Qt:选择的项目出现在 QGraphicsScene 的顶部

Qt 5.2 和 5.10 上 OpenGL 的差异

为啥所有选中的 QGraphicsItem 都没有收到 mouseMove 事件?

在 QGraphicsScene 中缩放和旋转的 QGraphicsPixmapItem 的奇怪绘图行为

line营销_line营销软件_line营销机器人_line营销大师