如何制作 Qt 交互式文本编辑小部件
Posted
技术标签:
【中文标题】如何制作 Qt 交互式文本编辑小部件【英文标题】:How to make a Qt interactive text editing widget 【发布时间】:2013-09-26 12:06:13 【问题描述】:我想开发一个有两个主要小部件的应用程序,一个是文本编辑器,另一个是图形查看器。
基本思想是让用户将鼠标悬停在文本区域中的任何代码块上,并且绘图的相关部分被选中或突出显示。
对于图形小部件,经过一些研究,似乎 QGraphicsScene 最符合要求,但我不确定文本编辑器使用哪个小部件,以便在将鼠标悬停在任何代码块上时给我一个信号(和还发送块的字符串参数“id”)。
也需要反向操作,因此当用户选择在图形视图中检查元素时,文本视图会滚动以查看关联的代码块并突出显示它(如谷歌浏览器的“检查元素”功能)。
【问题讨论】:
您是否尝试在要检测悬停的小部件的派生类中重新定义mouseMoveEvent
?
我个人不会为此使用 QGraphicsScene,而是使用 qml 或至少基于 opengl 的解决方案和 QtGui 用于图形查看器。您可以在文本小部件中以某种方式获取光标的位置,但不幸的是这有点棘手。但是,这确实看起来是 IMO 的一个奇特功能。 :-)
@Tab 我理解的问题是 op 还没有决定从哪个类派生
@Mahmoud 你能在 QGraphicsScene 中检测到实体吗?(因为我从未使用过它)。如果是,那么在文本编辑器中查找块的逻辑很容易。
@LaszloPapp 我认为 OpenGL 将拥有所有功能,但它增加了不必要的复杂性,我认为 QGraphicsScene 拥有我所需要的一切(到目前为止:D)。
【参考方案1】:
您可以使用QTextEdit::cursorForPosition
和QTextCursor::position
将鼠标坐标转换为文本中的位置。您可以使用此位置确定悬停的代码块。
您可以在文本编辑中选择任意代码块,如this answer 所述。
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;
注意:使用 public EmitItemHoverd 可能是一个问题,我只是为了解释可以通过所需更改对其进行保护的逻辑。
是的,我知道它的一半答案,但可以根据上面的相反逻辑来实现
【讨论】:
感谢 Tab 的回答 :) 覆盖 QGraphicsScene 的悬停信号的想法非常好,我绝对会考虑这个。 顺便说一句,“textEdit”不支持很多花哨的文本编辑功能(例如:行编号,行着色“奇数行的背景颜色与偶数行不同”,自动颜色关键字,.. .) 我仍在寻找解决这些问题的方法。 PS:如果您在开头添加此行,您的“OnItemHovered”功能会更好: ui->textEdit->moveCursor(QTextCursor::Start);因为如果块位于当前光标位置之前,现在它无法在代码中找到该块。 文本编辑支持html脚本,因此您可以通过它来管理样式表。对于 QTextCursor,我没有过多地测试该代码,我只是想看看我的想法是否可以实现,谢谢您的建议。 感谢 Tab,我已经对您进行了很多代码操作,但基本思想是关键,为了记录,我在代码区域使用了这个主题 qt-project.org/doc/qt-4.8/widgets-codeeditor.html,到目前为止它工作得很好:) 【参考方案3】:我会完全在 QML 中尝试这个。我会让文本编辑器成为一个文本区域列表(可能为所需的格式创建一个新的 QML 项)。列表中的每个项目实际上都是一个新创建的 QML 项目本身(适合转储到 .qml 文件中并在更高的项目中引用)。此时,您可以将这些项目中的每一个注入到左侧的 QML 视图中,仅添加鼠标处理程序以在悬停或单击该区域时触发。
因此,左侧是 QML 场景,由控制器管理和更新,控制器从右侧的项目列表中获取原始文本并尝试将其解析为新的 QML 类型。根据我脑海中的理论,它应该可以工作,并且会大大降低复杂性(尤其是在将鼠标点直接映射到正文中时)。
【讨论】:
多个文本区域的想法似乎非常适合映射鼠标悬停,恐怕它可能不是最好的解决方案,因为这是一个文本编辑器,因此用户可以稍后编辑,意思是想象一下上面截图的场景,用户后来决定在两个块之间添加一个新形状,程序如何检测到并创建一个新的文本区域?但我喜欢这个解决方案,并会尝试找到解决这个问题的方法,谢谢:) 您能否在保存时将列表压缩为单个文本文件,并根据***范围在加载时扩展它?那会很酷。以上是关于如何制作 Qt 交互式文本编辑小部件的主要内容,如果未能解决你的问题,请参考以下文章