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

5

我想开发一个应用程序,其中包含两个主要的小部件,一个是文本编辑器,另一个是图形查看器。

enter image description here

基本思想是让用户将鼠标悬停在文本区域的任何代码块上,就可以选择或突出显示相关部分的绘图。

对于图形小部件,在进行一些研究之后,似乎QGraphicsScene最符合要求,但我不确定要使用哪个小部件作为文本编辑器,以便在悬停在任何代码块上时给我发送信号(并且还要发送一个字符串参数“id”)。

反向操作也是必需的,因此当用户选择在图形视图中检查元素时,文本视图会滚动以查看关联的代码块并突出显示它(就像Google Chrome的“检查元素”功能)。


2
你尝试在想要检测悬停的小部件的派生类中重新定义 mouseMoveEvent 了吗? - Tab
1
我个人不会使用QGraphicsScene来实现这个,而是使用qml或至少基于opengl的解决方案,并使用QtGui作为图形查看器。你可以以某种方式获取文本小部件中光标的位置,但不幸的是这有点棘手。然而,我认为这确实是一个很棒的功能。 :-) - László Papp
1
据我理解,问题在于OP尚未决定从哪个类派生。 - Shf
1
@Mahmoud,你能在QGraphicsScene中检测实体吗?(因为我从未使用过它)。如果可以的话,那么在文本编辑器中查找块的逻辑就很容易了。 - Tab
1
@LaszloPapp 我认为OpenGL会有所有的特性,但它会增加不必要的复杂性,我认为QGraphicsScene已经拥有了我需要的一切(到目前为止:D)。 - Mahmoud Hassan
显示剩余6条评论
3个回答

4

您可以使用QTextEdit :: cursorForPosition QTextCursor :: position 将鼠标坐标转换为文本中的位置。 您可以使用此位置确定悬停代码块。

您可以按照此答案中描述的方式在文本编辑器中选择任意代码块。

QGraphicsScene 似乎是一个不错的选择,因为它包含您可能需要的所有功能。


2

要在场景中悬停物体时突出显示文本,您需要重新实现QGraphicsScene和QGraphicsItem(使用哪个取决于您)以通知主窗口查找并突出显示文本。以下是我使用QGraphicsPixmapItem突出显示场景中悬停对象文本的示例代码:


图形场景

 class GraphicScene : public QGraphicsScene
{
    Q_OBJECT
public:
    GraphicScene();

    void EmitItemHoverd(QString name)
    {
      emit SignalItemHovered(name);
    }


signals:
    void SignalItemHovered(QString);
};

图形元素:

#include "GraphicScene.h"

class GraphicItem : public QGraphicsPixmapItem
{
    QString itemName;
    GraphicScene * scene;
public:
    GraphicItem(GraphicScene *s, QString name);//name you can set from editor

    void hoverEnterEvent(QGraphicsSceneHoverEvent *event);

};
GraphicItem::GraphicItem(GraphicScene *s, QString name)
{
    scene = s;
    itemName = name;
    this->setAcceptHoverEvents(true);
}

void GraphicItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
{
    scene->EmitItemHoverd(itemName);
}

在MainWindow构造函数中连接。
connect(scene,SIGNAL(SignalItemHovered(QString)),this,SLOT(OnItemHovered(QString)));

这里是插槽:

void MainWindow::OnItemHovered(QString name)
{
   ui->textEdit->find(name);
  QTextCursor tc = ui->textEdit->textCursor();
  tc.select(QTextCursor::WordUnderCursor);    
  ui->textEdit->find("}");
  QTextCursor tc1 = ui->textEdit->textCursor();
  tc1.select(QTextCursor::WordUnderCursor);
  int pos2 = tc1.selectionStart();

  tc.setPosition(pos2,QTextCursor::KeepAnchor);
  ui->textEdit->setTextCursor(tc);
}

并且使用逻辑绘制:

    GraphicItem * item = new GraphicItem(scene,"Circle");

    QPixmap  map(50,50);
    QPainter * painter= new QPainter(&map);
    painter->setBrush(QBrush(Qt::red,Qt::SolidPattern));
    painter->drawEllipse(20,20,15,15);
    item->setPixmap(map);

    scene->addItem(item);
    ui->graphicsView->update();
    delete painter;

注意:在这里使用公共的EmitItemHoverd可能会有问题,我只是为了解释逻辑而使用它,您可以通过必要的更改将其设置为受保护状态。

是的,我知道这只是答案的一半,但是可以根据上述相反的逻辑进行实现。


1
感谢Tab提供的答案 :) 覆盖QGraphicsScene悬停信号的想法非常好,我一定会考虑这个。 - Mahmoud Hassan
顺便说一下,“textEdit”不支持很多花哨的文本编辑功能(比如:行号、行颜色“奇数行和偶数行有不同的背景颜色”、自动颜色关键字等)。我仍在寻找解决这些问题的方法。另外,如果你在“OnItemHovered”函数开头添加以下代码,它将会更好地工作: ui->textEdit->moveCursor(QTextCursor::Start); 因为现在如果块位于当前光标位置之前,它无法在代码中找到该块。 - Mahmoud Hassan
文本编辑器支持HTML脚本,因此您可以通过它来管理样式表。至于QTextCursor,我并没有对那段代码进行过多测试,只是想看看我的想法是否可实现,感谢您的建议。 - Tab
2
谢谢Tab,我对你的代码进行了很多修改,但基本思路是关键,记录一下,我使用了这个主题http://qt-project.org/doc/qt-4.8/widgets-codeeditor.html作为代码区域,目前效果非常好 :) - Mahmoud Hassan

1
我会尝试完全使用QML进行此操作。 我将把文本编辑器制作成文本区域的列表(可能为所需格式创建一个新的QML项)。 列表中的每个项目本身都是新创建的QML项(适合转储到.qml文件中并在更高级别的项中引用)。 在这一点上,您可以将每个项目注入到左侧的QML视图中,仅在悬停或单击该区域时添加鼠标处理程序。 左侧是由控制器管理和更新的QML场景,该控制器从右侧的项目列表中获取原始文本,并尝试将其解析为新的QML类型。 根据我脑中的理论,它应该能够正常工作,并且可以减少大量复杂性(特别是在将鼠标点直接映射到文本主体时)。

多个文本区域的想法似乎非常适合映射鼠标悬停,但我担心这可能不是最好的解决方案,因为这是一个文本编辑器,所以用户可以稍后进行编辑。想象一下上面截图的情景,如果用户后来决定在两个块之间添加一个新形状,程序如何检测并创建一个新的文本区域?但我喜欢这个解决方案,并将尝试找到一个解决此问题的方法,谢谢 :) - Mahmoud Hassan
1
你能否在保存时将列表压缩成单个文本文件,并根据顶层作用域在加载时进行扩展?那将非常酷。 - Thadeux

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接