QTextEdit内拖入图片——QtWidgets

 前言

QTextEdit是用来编辑和展示文本和富文本的一个控件。我之前一直拿它当纯文本编辑器(QPlainTextEdit)使,一直没啥机会去用一下他的富文本功能。

这次有时间了,准备做一个可以添加图片的编辑框:拖入即可添加到编辑框。

 

效果图

QTextEdit内拖入图片——QtWidgets_第1张图片

实现的两种方式

有两种方式,一种是根据动作想到了Drag 、Drop来实现;另一种是QTextEdit自带的方法实现。

拖入、落下事件来实现

一般在光标处添加图片,代码为

  QImage img = ...
  textDocument->addResource(QTextDocument::ImageResource, QUrl("myimage"), img);
  cursor.insertImage("myimage");

 现在我们重写QTextEdit,命名为MyTextEdit,然后在落下事件中,获取MineData,将其转化为QImage,最后根据上面的方法,也就实现了拖入图片功能了

void MyTextEdit::dragEnterEvent(QDragEnterEvent *e)
{
    e->acceptProposedAction();
}

void MyTextEdit::dropEvent(QDropEvent *e)
{
    QString url=e->mimeData()->urls().first().toLocalFile();

    if(e->mimeData()->hasImage())
    {
        //这只是个名字 供后续调用的名字
        QUrl name ( QString ( "file://%1" ).arg ( url ) );

        //获取图片 并插入到光标处
        QImage image = QImageReader ( url ).read();
        QTextDocument * textDocument = this->document();
        document()->addResource( QTextDocument::ImageResource, name, QVariant ( image ) );

        textCursor().insertImage(name.toString());
    }
}

QTextEdit自带的方法实现

后来,我发现QTextEdit对插入图片等数据都有固定的方法可实现。通过方法canInsertFromMimeData对插入的数据进行筛选,

然后在insertFromMimeData方法中根据不同类的数据进行操作添加。不过我经过测试发现:source->hasImage()条件的,不知情况下能满足,经过我拖入的或者复制粘贴的,都不是hasImage(),所以谁能解决我的疑问?!

bool MyTextEdit::canInsertFromMimeData(const QMimeData *source) const
{

    return source->hasImage()||source->hasUrls()||QTextEdit::canInsertFromMimeData(source);

}

void MyTextEdit::insertFromMimeData(const QMimeData *source)
{
    if(source->hasImage())
    {
        qDebug()<<"hasImage-------------------";
        static int i=1;
        QUrl name(QString("imgName_%1").arg(i));
        QImage img=qvariant_cast(source->imageData());
        document()->addResource(QTextDocument::ImageResource,name,img);

        textCursor().insertImage(name.toString());
        i++;
    }
    else if (source->hasUrls())
    {
        qDebug()<<"urls-----------------------------";
        foreach (QUrl url, source->urls())
        {
            QFileInfo info(url.toLocalFile());
            if (QImageReader::supportedImageFormats().contains(info.suffix().toLower().toLatin1()))
            {
                QImage image(info.filePath());
                if (!image.isNull())
                {
                    document()->addResource(QTextDocument::ImageResource, url, image);
                    textCursor().insertImage(url.toString());
                }
            }
            else{
                QFile file(url.toLocalFile());
                if(file.open(QIODevice::ReadOnly|QIODevice::Text))
                    textCursor().insertText(file.readAll());
            }

        }
    }else{
        qDebug()<<"insertFromMimeData--------------------";
        QTextEdit::insertFromMimeData(source);
    }

}

官方源码说明 

我在QTextEdit看到了以下一段话,解释了我以上两个方法的可行性:

QTextEdit also supports custom drag and drop behavior. By default, QTextEdit will insert plain text, HTML and rich text when the user drops data of these MIME types onto a document. Reimplement canInsertFromMimeData() and insertFromMimeData() to add support for additional MIME types.

还有我很好奇,QTextEdit底层是如何写的canInsertFromMimeDatainsertFromMimeData方法:它是另写了一个控制类QWidgetTextControl来操作,从以下源码中,我们可以清楚的看到它能够支持什么类型插入,还有根据不同的数据类型,进行的不同的处理,这些都是默认自带的。

bool QWidgetTextControl::canInsertFromMimeData(const QMimeData *source) const
{
    Q_D(const QWidgetTextControl);
    if (d->acceptRichText)
        return (source->hasText() && !source->text().isEmpty())
            || source->hasHtml()
            || source->hasFormat(QLatin1String("application/x-qrichtext"))
            || source->hasFormat(QLatin1String("application/x-qt-richtext"));
    else
        return source->hasText() && !source->text().isEmpty();
}

void QWidgetTextControl::insertFromMimeData(const QMimeData *source)
{
    Q_D(QWidgetTextControl);
    if (!(d->interactionFlags & Qt::TextEditable) || !source)
        return;

    bool hasData = false;
    QTextDocumentFragment fragment;
#ifndef QT_NO_TEXTHTMLPARSER
    if (source->hasFormat(QLatin1String("application/x-qrichtext")) && d->acceptRichText) {
        // x-qrichtext is always UTF-8 (taken from Qt3 since we don't use it anymore).
        const QString richtext = QLatin1String("")
                + QString::fromUtf8(source->data(QLatin1String("application/x-qrichtext")));
        fragment = QTextDocumentFragment::fromHtml(richtext, d->doc);
        hasData = true;
    } else if (source->hasHtml() && d->acceptRichText) {
        fragment = QTextDocumentFragment::fromHtml(source->html(), d->doc);
        hasData = true;
    } else {
        QString text = source->text();
        if (!text.isNull()) {
            fragment = QTextDocumentFragment::fromPlainText(text);
            hasData = true;
        }
    }
#else
    fragment = QTextDocumentFragment::fromPlainText(source->text());
#endif // QT_NO_TEXTHTMLPARSER

    if (hasData)
        d->cursor.insertFragment(fragment);
    ensureCursorVisible();
}

还有就是QTextEdit支持剪贴板(clipboard)的,从源码中,你可以看到它对复制粘贴等的一系列处理。 这个我就不列举源码了。

结束语 

感觉每次深入研究一个经常用的小控件,都收获满满(*^▽^*)!

 

你可能感兴趣的:(Qt,Widgets)