How to click on the image, hold from a corner of it, and resize the image in the QTextEdit? Or at least how to get an image under cursor/that is selected in order to change widt
The above is quite common requirement but not straight forward to implement in Qt. The resizing frame of an image within a QTextEdit is the tricky part. I use a different approach. I draw a widget on top of the QTextEdit as a rubber band around the image. To achieve this I have done the following:
I have implemented another widget(inheriting from QWidget) that draws itself like a dashed-line frame. When provided the right size it will draw itself like rubber band selection around the image and will provide you with the new image size, once the user has ended resizing the rubber band. Of course you might resize the image too during resizing of the rubber band if you use the virtual resizeEvent(...) function of the rubber band widget and emit your own signal. As a parent of the rubber band widget set the QTextEdi->viewport() to get proper viewport position of you rubberband widget.
Create another class(MyTextEditDecorator) that simply inherits from QObject and install itself as an event filter for the QTextEdit and the QTextEdit viewport. It will also provide good isolation of the rubber band functionality from the rest of the code you might already have. Inside the MyTextEditDecorator::eventFilter(...) function catch the MouseButtonPress, MouseButtonRelease, Paint and Resize events. Show the rubber band widget, when a user clicks within an image or image border, i.e. when the cursor format is QTextImageFormat and hide it when the text cursor is outside of an image format.
If you want the rubber band selection to appear when a user moves the text cursor via a keyboard for example you might want to hook to the QTextEdit::cursorPositionChanged(). For my purposes I also needed the currentCharFormatChanged() and textChanged() signals in cases when text is entered and an image format is newly created. You will also need to find the image x,y position within the viewport to position the rubber band widget properly around the image. I use the QTextEdit::cursorRect(imageSelectedCursor). If you support different image alignments, be prepared to adjust for it too. Another useful function to find X,Y screen positions is QTextLayout::lineForTextPosition(textCursor.position()) to get the proper QTextLine and QTextLine::rect().
To get the image resizing with rubber band needs a lot of extra effort and read the above as a guide. I have implemented it personally and it works in a professional text editing application. Sorry for not posting the complete solution here. It is long and has a copyright. Hope that the above guide will help someone. I have tested several solutions, but this one is the only one that provides full and encapsulated inside editor image rubber band resizing without messing with the QTextEdit code and the Qt library internals.
Here how I have implemented:
void AdvancedTextEdit::resizeImage()
{
QTextBlock currentBlock = m_textEdit->textCursor().block();
QTextBlock::iterator it;
for (it = currentBlock.begin(); !(it.atEnd()); ++it)
{
QTextFragment fragment = it.fragment();
if (fragment.isValid())
{
if(fragment.charFormat().isImageFormat ())
{
QTextImageFormat newImageFormat = fragment.charFormat().toImageFormat();
QPair<double, double> size = ResizeImageDialog::getNewSize(this, newImageFormat.width(), newImageFormat.height());
newImageFormat.setWidth(size.first);
newImageFormat.setHeight(size.second);
if (newImageFormat.isValid())
{
//QMessageBox::about(this, "Fragment", fragment.text());
//newImageFormat.setName(":/icons/text_bold.png");
QTextCursor helper = m_textEdit->textCursor();
helper.setPosition(fragment.position());
helper.setPosition(fragment.position() + fragment.length(),
QTextCursor::KeepAnchor);
helper.setCharFormat(newImageFormat);
}
}
}
}
}
Of course I have implemented also the ResizeImageDialog dialog's getNewSize(this, newImageFormat.width(), newImageFormat.height()); function that gets the current size of image and lets user to chnage the size, and returns the new size of image as a QPair. This is not hard to do. See here for the implementation of the dialog.