Question

I'd like to make my QRubberband instance user resizeable. I've seen this question here but there isn't a solution.

The use case is that the user can drag out a selection marquee over a photo and then make fine adjustments by dragging on the QRubberband margins to change geometry, or reposition existing geometry by dragging the selection. I have the repositioning implemented but I am wondering about resize handles for changing the geometry of the QRubberband.

Is it possible to use QSizeGrip here? Barring that, is there a standard way of checking for mouse-within-margin type events within Qt or some other way to implement this? This is for a research app that doesn't need or warrant lots of effort on this feature but it would be good to have.

Was it helpful?

Solution

Yes, it's possible. Here is the implementation:

Header:

class Resizable_rubber_band : public QWidget {
public:
  Resizable_rubber_band(QWidget* parent = 0);

private:
  QRubberBand* rubberband;
  void resizeEvent(QResizeEvent *);

};

Source:

Resizable_rubber_band::Resizable_rubber_band(QWidget *parent) : QWidget(parent) {
  //tell QSizeGrip to resize this widget instead of top-level window
  setWindowFlags(Qt::SubWindow);
  QHBoxLayout* layout = new QHBoxLayout(this);
  layout->setContentsMargins(0, 0, 0, 0);
  QSizeGrip* grip1 = new QSizeGrip(this);
  QSizeGrip* grip2 = new QSizeGrip(this);
  layout->addWidget(grip1, 0, Qt::AlignLeft | Qt::AlignTop);
  layout->addWidget(grip2, 0, Qt::AlignRight | Qt::AlignBottom);
  rubberband = new QRubberBand(QRubberBand::Rectangle, this);
  rubberband->move(0, 0);
  rubberband->show();
  show();
}

void Resizable_rubber_band::resizeEvent(QResizeEvent *) {
  rubberband->resize(size());
}

Usage: (ui->label is the label used for displaying the image to be cropped)

Resizable_rubber_band* band = new Resizable_rubber_band(ui->label);
band->move(100, 100);
band->resize(50, 50);
band->setMinimumSize(30, 30);

screenshot

OTHER TIPS

In case anyone else wanders in here off Google with the intent to use this with PyQt, here's the equivalent Python code to @pavel-strakhov's C++ example and I can confirm that it works for me on *buntu Linux 14.04 LTS with the system-provided Python 3.4 and PyQt 5.2.1.

(With the caveat that my chosen widget theme doesn't know how to rotate the QSizeGrip in the top-left corner, so both corners have identical-looking grips.)

Source:

class ResizableRubberBand(QWidget):
    """Wrapper to make QRubberBand mouse-resizable using QSizeGrip

    Source: http://stackoverflow.com/a/19067132/435253
    """
    def __init__(self, parent=None):
        super(ResizableRubberBand, self).__init__(parent)

        self.setWindowFlags(Qt.SubWindow)
        self.layout = QHBoxLayout(self)
        self.layout.setContentsMargins(0, 0, 0, 0)

        self.grip1 = QSizeGrip(self)
        self.grip2 = QSizeGrip(self)
        self.layout.addWidget(self.grip1, 0, Qt.AlignLeft | Qt.AlignTop)
        self.layout.addWidget(self.grip2, 0, Qt.AlignRight | Qt.AlignBottom)

        self.rubberband = QRubberBand(QRubberBand.Rectangle, self)
        self.rubberband.move(0, 0)
        self.rubberband.show()
        self.show()

    def resizeEvent(self, event):
        self.rubberband.resize(self.size())

Usage:

self.band = ResizableRubberBand(ui.label)
self.band.move(100, 100)
self.band.resize(50, 50)
self.band.setMinimumSize(30, 30)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top