QTextBrowser - how to identify an image from a mouse position

I use QTextBrowser to display QTextBrowser text, including several images, each of which is indicated by an HTML <img> and added as resources using QTextDocument::addResource() .

What I would like to do is in the context menu handler (i.e. with the available mouse position), determine the image that was clicked on. You can indicate whether a click is above the image because cursorForPosition(event->pos()).block().text() returns a line starting with Unicode 0xFFFC. Unfortunately, the same row is returned for each image in the view.

You can get all the formats used with QTextDocument::allFormats() , determine which ones are image formats, and get their image resource name. Unfortunately, there seems to be no way to get their actual display position or bounding box.

+4
source share
1 answer

From the documentation :

Embedded images are represented by the object replacement symbol (0xFFFC in Unicode), which has a QTextImageFormat associated with it. The image format is indicated by the name using setName (), which is used to search for the image.

You can use charFormat().toImageFormat().name() on the cursor to retrieve the URL of the image. The following is a self-sufficient example. There are two notable details:

  • The cursor sometimes points to one character in front of the image. Thus, a workaround; this seems to be necessary for both Qt 4.8.5 and 5.1.1.

  • Pop-up menus should be displayed asynchronously so as not to block the rest of the application. The sample code provided in the documentation is a source of bad user experience and should be considered an evil abomination. All widgets can automatically delete themselves when they close, so the menu will not flow. A QPointer used only to demonstrate this fact. It keeps track of the lifetime of the menu and is zero when the menu deletes itself.

 #include <QApplication> #include <QTextBrowser> #include <QImage> #include <QPainter> #include <QMenu> #include <QContextMenuEvent> #include <QTextBlock> #include <QPointer> #include <QDebug> class Browser : public QTextBrowser { QPointer<QMenu> m_menu; protected: void contextMenuEvent(QContextMenuEvent *ev) { Q_ASSERT(m_menu.isNull()); // make sure the menus aren't leaking m_menu = createStandardContextMenu(); QTextCursor cur = cursorForPosition(ev->pos()); QTextCharFormat fmt = cur.charFormat(); qDebug() << "position in block" << cur.positionInBlock() << "object type" << cur.charFormat().objectType(); if (fmt.objectType() == QTextFormat::NoObject) { // workaround, sometimes the cursor will point one object to the left of the image cur.movePosition(QTextCursor::NextCharacter); fmt = cur.charFormat(); } if (fmt.isImageFormat()) { QTextImageFormat ifmt = fmt.toImageFormat(); m_menu->addAction(QString("Image URL: %1").arg(ifmt.name())); } m_menu->move(ev->globalPos()); m_menu->setAttribute(Qt::WA_DeleteOnClose); // the menu won't leak m_menu->show(); // show the menu asynchronously so as not to block the application } }; void addImage(QTextDocument * doc, const QString & url) { QImage img(100, 100, QImage::Format_ARGB32_Premultiplied); img.fill(Qt::white); QPainter p(&img); p.drawRect(0, 0, 99, 99); p.drawText(img.rect(), url); doc->addResource(QTextDocument::ImageResource, QUrl(url), img); } int main(int argc, char *argv[]) { QApplication a(argc, argv); QTextDocument doc; Browser browser; doc.setHtml("<img src=\"data://image1\"/><br/><img src=\"data://image2\"/>"); addImage(&doc, "data://image1"); addImage(&doc, "data://image2"); browser.show(); browser.setDocument(&doc); return a.exec(); } 
+1
source

Source: https://habr.com/ru/post/1501318/


All Articles