ryan0270
ryan0270

Reputation: 1217

Custom mouse interaction for custom QTextObject in QTextEdit

I have a custom widget that I want to add to a QTextEdit (via drag/drop) and then allow the user to double-click on the widget to open a separate edit window.

Right now I have it to where I can drag the widget onto the QTextEdit and an image is added to represent the widget in the document. This is done via a wrapper class that implements QTextObjectInterface.

Now I need to figure out how to handle mouse events so that when the user clicks in the image, the program knows to bring up a custom edit GUI.

Roughly what I have right now is,

class MyWidget : public QWidget
{ ... }

class MyWidgetWrapper : public QObject, QTextObjectInterface
{
    Q_OBJECT
    Q_INTERFACES(QTextObjectInterface)
    ....

    void drawObject(QPainter *painter, const QRectF &rect, QTextDocument *doc, int posInDocument, const QTextFormat &format)
    {
        MyWidgetWrapper *tmp = qvariant_cast<MyWidgetWrapper*>(format.property(1));
        painter->drawImage(rect, tmp->mMyWidget.getImage());
    }

    private:
    MyWidget mMyWidget;
}

and then, in my custom QTextEdit class I have

bool MyTextEdit::initialize()
{
    MyWidgetWrapper *tmp = new MyWidgetWrapper();
    document()->documentLayout()->registerHandler(MyWidgetWrapperFormat, tmp);
    return true;
}

void MyTextEdit::insertFromMimeData(const QMimeData *source)
{
    if(source->hasFormat("application/x-MyWidgetWrapper"))
    {
        MyWidgetWrapper *widgetWrapper = new MyWidgetWrapper(this);

    QTextCharFormat charFormat;
    charFormat.setObjectType(MyWidgetWrapperFormat);
    charFormat.setProperty(MyWidgetWrapperData, QVariant::fromValue(widgetWrapper));

    QTextCursor cursor = textCursor();
    cursor.insertText(QString(QChar::ObjectReplacementCharacter), charFormat);
    setTextCursor(cursor);
    }
}

Upvotes: 3

Views: 841

Answers (1)

ryan0270
ryan0270

Reputation: 1217

Ok, after playing around I managed something that works. I'm not sure if it's the best solution, though. I guess I was hoping for something that would more directly give me the object that was clicked on. As you can image, this solution gets annoying as I start to add many custom QTextObjects since I will need a bunch of if ... else if ... statements

Basically, since I already have my own subclass of QTextEdit, I implemented my own handler for mouseDoubleClickEvent

void MyTextEdit::mouseDoubleClickEvent(QMouseEvent *event)
{
    QPoint eventPos = event->pos();
    QTextCursor cursor = cursorForPosition(eventPos);

    // now check to see if we've moved the cursor to the space
    // before or after the actual click location
    QRect rect = cursorRect();
    if(rect.x() < eventPos.x())
        cursor.movePosition(QTextCursor::Right);

    // charFormat is for the object BEFORE the 
    // cursor postion
    int type = cursor.charFormat().objectType();
    if(type == MyWidgetWrapperFormat)
    {
        MyWidgetWrapper *ed = qvariant_cast<MyWidgetWrapper*>(cursor.charFormat().property(1));

        mFileDialog->setFileMode(QFileDialog::ExistingFile);
        mFileDialog->setNameFilter("Images (*.bmp *.jpg)");

        if(mFileDialog->exec())
        {
            QStringList filenames = mFileDialog->selectedFiles();
            QString filename = filenames.at(0);
            QImage image(filename);
            ed->MyWidget()->setImage(image);
        }
    }
}

Upvotes: 2

Related Questions