How to resize a frameless widget in Qt - qt

I am researching on how to resize the frameless widget in Qt 5.1. Due to cross-platform consideration, Windows-related codes will not be appropriate.
Now my method is: when a user hovers mouse at the edge of the window(widget),cursor shape changes to hint the window can be resized at that time. After clicking and then drag, a rubberband is being shown to demonstrate the rectangle area that the window would resize to. Once the user releases the mouse, rubberband disappears, and the window then resize to the desired size. Have I made it clear?
Since Qt can't make drawing directly on the screen, as a makeshift, a full screenshot(put in a QLabel) is utilized to simulate the actual screen, and a rubberband can then be constructed in the full-screen QLabel. It seems to the users that they are dragging the window in the real window screen.
My problem is: after the user clicked the main widget,though a full-screen QLabel is shown, the rubberband refuses to appear. Instead, only after you release mouse first and then click-drag again can the rubberband appear.
Although I have sent one "MouseButtonRelease" event to the main widget and a "MouseMove" event to the label, it doesn't seem to work. Any hint or suggestion will be highly appreciated, thanks a lot!
(To simplify the code, any other extra codes have been removed)
mainwidget.h
class MainWidget : public QWidget
{
Q_OBJECT
public:
MainWidget(QWidget *parent = 0);
~MainWidget();
private:
QScreen *screen;
QLabel *fullScreenLabel;
QPixmap fullScreenPixmap;
QRubberBand *rubberBand;
protected:
virtual bool eventFilter(QObject *o, QEvent *e);
void mousePressEvent(QMouseEvent *e);
};
mainwidget.cpp
MainWidget::MainWidget(QWidget *parent)
: QWidget(parent)
{
this->setWindowFlags(Qt::FramelessWindowHint);
screen = QGuiApplication::primaryScreen();
rubberBand=NULL;
fullScreenLabel=new QLabel();
fullScreenLabel->installEventFilter(this);
resize(600,450);
}
MainWidget::~MainWidget()
{
delete fullScreenLabel;
}
bool MainWidget::eventFilter(QObject *o, QEvent *e)
{
if(o!=fullScreenLabel)
return QWidget::eventFilter(o,e);
QMouseEvent *mouseEvent=static_cast<QMouseEvent*>(e);
if(mouseEvent->type()==QEvent::MouseMove)
{
qDebug()<<"label mouse move: "<< mouseEvent->pos();
if(!rubberBand)
{
rubberBand=new QRubberBand(QRubberBand::Rectangle,fullScreenLabel);
rubberBand->setGeometry(QRect(this->pos(),QSize()));
rubberBand->show();
}
rubberBand->setGeometry(QRect(this->pos(),mouseEvent->pos()).normalized());
return true;
}
if((mouseEvent->button()==Qt::LeftButton)
&& (mouseEvent->type()==QEvent::MouseButtonRelease))
{
if(rubberBand)
{
rubberBand->hide();
delete rubberBand;
rubberBand=NULL;
}
return true;
}
return false;
}
void MainWidget::mousePressEvent(QMouseEvent *e)
{
if(screen)
{
fullScreenPixmap=QPixmap();
fullScreenPixmap=screen->grabWindow(0,0,0,-1,-1);
}
fullScreenLabel->setPixmap(fullScreenPixmap);
fullScreenLabel->showFullScreen();
QMouseEvent clickEvent(QEvent::MouseButtonRelease,
e->pos(),
Qt::LeftButton,
Qt::LeftButton,
Qt::NoModifier);
qApp->sendEvent(this,&clickEvent);
QMouseEvent moveEvent(QEvent::MouseMove,
this->pos(),
Qt::NoButton,
Qt::NoButton,
Qt::NoModifier);
qApp->sendEvent(fullScreenLabel,&moveEvent);
}

You may research how it's done in Qt - QSizeGrip. There are same question

Related

Move QGraphicsItem only when pressing inside the shape. Otherwise, drag scene

I have a QGraphicsView with a bigger QGraphicsScene that can be dragged.
In the QGraphicsScene I have a subclassed QGraphicsItem (TestItem) that displays a QGraphicsPixmapItem, which can have random shapes.
(I don't use QGraphicsPixmapItem directly because of extra functionality to be implemented in the future)
I want this item to be movable, but only if the user presses within the shape of the item. If outside the shape, but still inside the boundingRectangle, I want the scene behind it to be dragged. This because the boundingRectangle can be much bigger than the shape and the user doesn't see it, so it would be weird trying to drag the scene near the Pixmap and it not working.
This is my subclassed item:
TestItem::TestItem(QPointF position, QPixmap testImage, double width,
double length, QGraphicsItem * parent):
QGraphicsItem(parent),
m_boundingRect(QRectF(0,0,5, 5)),
m_dragValid(false),
m_path(QPainterPath()),
mp_image(new QGraphicsPixmapItem(this))
{
setBoundingRect(QRectF(0,0,width,length));
setPos(position - boundingRect().center());
setFlag(QGraphicsItem::ItemIsMovable);
mp_image->setPixmap(testImage.scaled(width, length));
m_path = mp_image->shape();
}
QPainterPath TestItem::shape()
{
return m_path;
}
QRectF TestItem::boundingRect() const
{
return m_boundingRect;
}
void TestItem::setBoundingRect(QRectF newRect)
{
prepareGeometryChange();
m_boundingRect = newRect;
}
I've tried overriding the mouse events like this, but all it brings me is no functionality at all when outside the shape but inside the bounding rectangle
void TestItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
if(shape().contains(event->pos()))
{
QGraphicsItem::mousePressEvent(event);
m_dragValid = true;
}
}
void TestItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
if(m_dragValid)
QGraphicsItem::mouseMoveEvent(event);
}
void TestItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
if(m_dragValid)
QGraphicsItem::mouseReleaseEvent(event);
m_dragValid = false;
}
which of course makes sense, but I wouldn't know how to implement the dragging of the scene, since it's the scene itself that sends the mouse events to the graphics item.
(My QGraphicsView is setup to DragMode QGraphicsView::ScrollHandDrag)
Anyone have ideas?
I figured it out. I only needed to add a event->ignore(); to my mouse events.
void TestItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
if(shape().contains(event->pos()))
{
QGraphicsItem::mousePressEvent(event);
m_dragValid = true;
}
else
event->ignore();
}
void TestItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
if(m_dragValid)
QGraphicsItem::mouseMoveEvent(event);
else
event->ignore();
}
void TestItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
if(m_dragValid)
QGraphicsItem::mouseReleaseEvent(event);
else
event->ignore();
m_dragValid = false;
}
You just need to enable QGraphicsItem::ItemClipsToShape flag:
The item clips to its own shape. The item cannot draw or receive mouse, tablet, drag and drop or hover events outside its shape. It is disabled by default.

QRubberBand doesn't work

I am using QRubberBand to draw a selection box on my QWidget that displays a QImage.
I am using the code exactly as it is shown in the documentation, but it doesn't work. I get no errors, but it does act strange. Instead of displaying a selection box when I hold my left button down and drag it across my QWidget which is painted with the QImage it just makes one of my buttons on my interface disappear and reappear based on my left button click. I should also add that the button that disappears isn't apart of the QWidget, or even apart of the parent QObject that creates the QWidget.
void Widget::mousePressEvent(QMouseEvent *event)
{
origin = event->pos();
if (!rubberBand)
rubberBand = new QRubberBand(QRubberBand::Rectangle, this);
rubberBand->setGeometry(QRect(origin, QSize()));
rubberBand->show();
}
void Widget::mouseMoveEvent(QMouseEvent *event)
{
rubberBand->setGeometry(QRect(origin, event->pos()).normalized());
}
void Widget::mouseReleaseEvent(QMouseEvent *event)
{
rubberBand->hide();
// determine selection, for example using QRect::intersects()
// and QRect::contains().
}
Any help is appreciated.
Thanks
It is totally my fault. I failed to set my pointer as NULL in my header.
Instead of this :
QRubberBand *rubberBand {rubberBand = NULL};
I just did :
QRubberBand *rubberBand;

How to create a draggable (borderless and titleless) top level window in QT

I'd appreciate help creating a top-level window in Qt with the following characteristics. The window must be:
Borderless, titleless and lie on top of all other windows on the desktop (easy)
Draggable by clicking and dragging anywhere inside it (this what I need help with)
Constrained to the top border of the desktop while dragging (relatively easy)
Basically, I'm trying to collapse our QT application to a top-level icon on the top border of the desktop.
You'll find the answer to the first part in: Making a borderless window with for Qt, and the answer to the second part in Select & moving Qwidget in the screen.
Combining the two, and adding the last part is straightforward.
Here's how you could do it:
#include <QtGui>
class W: public QWidget
{
Q_OBJECT
Set up a borderless widget with a few buttons to lock/unlock and quit:
public:
W(QWidget *parent=0)
: QWidget(parent, Qt::FramelessWindowHint), locked(false)
{
QPushButton *lock = new QPushButton("Lock");
QPushButton *unlock = new QPushButton("Unlock");
QPushButton *quit = new QPushButton("&Quit");
connect(lock, SIGNAL(clicked()), this, SLOT(lock()));
connect(unlock, SIGNAL(clicked()), this, SLOT(unlock()));
connect(quit, SIGNAL(clicked()),
QApplication::instance(), SLOT(quit()));
QHBoxLayout *l = new QHBoxLayout;
l->addWidget(lock);
l->addWidget(unlock);
l->addWidget(quit);
setLayout(l);
}
public slots:
void lock() {
locked = true;
move(x(), 0); // move window to the top of the screen
}
void unlock() { locked = false; }
Do the mouse handling:
protected:
void mousePressEvent(QMouseEvent *evt)
{
oldPos = evt->globalPos();
}
void mouseMoveEvent(QMouseEvent *evt)
{
const QPoint delta = evt->globalPos() - oldPos;
if (locked)
// if locked, ignore delta on y axis, stay at the top
move(x()+delta.x(), y());
else
move(x()+delta.x(), y()+delta.y());
oldPos = evt->globalPos();
}
private:
bool locked;
QPoint oldPos;
};

Why is the widget not getting resizeEvent?

I am trying to implement a new custom scrollbar. In order to do so, I have placed it onto the parent manually with this->setParent(area);
class QMacScrollBar : public QScrollBar
{
Q_OBJECT
public:
QMacScrollBar(QAbstractScrollArea *area, Qt::Orientation orientation, QWidget *parent = 0);
virtual void paintEvent ( QPaintEvent * );
QAbstractScrollArea *area;
signals:
public slots:
virtual void resizeEvent(QResizeEvent *event);
};
QMacScrollBar::QMacScrollBar(QAbstractScrollArea *area, Qt::Orientation orientation, QWidget *parent) :
QScrollBar(area)
{
this->setMouseTracking(true);
this->setOrientation(orientation);
this->setParent(area);
this->area = area;
}
void QMacScrollBar::resizeEvent(QResizeEvent *event){
QRect geometry = QRect(QPoint(0, 0), event->size());
if (area != NULL){
geometry.setHeight(area->height());
geometry.moveRight(area->width());
geometry.adjust(-5, 0, -5, 0);
this->setGeometry(geometry);
}
QScrollBar::resizeEvent(event);
}
I do get the first few resizes, but none after that. So far my guess is that when I resize the window, the QScrollArea doesnt actually resize, it just hides more of the viewport. I need the resize event because I need to move the place that I display the bar. How do I fix this?
EDIT: The only resizes I am getting are the ones that I spawn via connecting to the underlying scrollbar's setRange signal.

Problem with drawing focus frame in Qt

I'm trying to create custom widget inheriting QFrame. All works fine, but I'm unable to draw the focus rectangle around my widget. Below is the sample code I use for drawing:
frame.h
class Frame : public QFrame {
Q_OBJECT
public:
Frame(QWidget *parent = 0);
~Frame();
protected:
void paintEvent(QPaintEvent *event);
private:
Ui::Frame *ui;
};
frame.cpp
Frame::Frame(QWidget *parent) :
QFrame(parent),
ui(new Ui::Frame)
{
ui->setupUi(this);
setFocusPolicy(Qt::ClickFocus);
}
Frame::~Frame()
{
delete ui;
}
void Frame::paintEvent(QPaintEvent *event)
{
QFrame::paintEvent(event);
if (hasFocus()) {
QStylePainter painter(this);
QStyleOptionFocusRect option;
option.initFrom(this);
option.backgroundColor = palette().dark().color();
painter.drawPrimitive(QStyle::PE_FrameFocusRect, option);
}
}
What I mean by 'unable to draw focus frame' is that when you click a standard widget that accepts focus (let's say QLineEdit), it has a blue rectangle drawn around it. When I click my widget there is no such rectangle drawn. Are there any more things I should do besides setting focusPolicy on my widget?
It might have something to do with the style your app is using. When I try your code with the "gtk" and "cleanlooks" style, no focus rectangle is drawn. With "plastique" and "windows" it is. Since I'm on Linux, I cannot test "windowsxp" and "macintosh". Try running with the -style option and see what happens.
try also
setFocusPolicy(Qt::StrongFocus);
setAttribute( Qt::WA_MacShowFocusRect);

Resources