Why is the widget not getting resizeEvent? - qt

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.

Related

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;
};

How to resize a frameless widget in 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

How override cursor when dragging out the app?

Is it possible to override standart "Stop" (crossed circle) cursor when I drag and drop outside the main window? I have very simple code and that is enough for me. I drag PushButton outside the main window and on release mouse button I get window where mouse was released. Like a standart Windows Spy. So how can I override cursor outside the main window?
header
class DDButton : public QPushButton
{
Q_OBJECT
public:
explicit DDButton(QWidget *parent = 0);
signals:
public slots:
private:
void mousePressEvent(QMouseEvent *event);
};
cpp
void DDButton::mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton) {
QDrag *drag = new QDrag(this);
QMimeData *mimeData = new QMimeData;
drag->setMimeData(mimeData);
drag->setPixmap(cursor.pixmap());
drag->setHotSpot(QPoint(0,0));
//This block not working
QCursor cursor(Qt::OpenHandCursor);
drag->setDragCursor(cursor.pixmap(), Qt::IgnoreAction);
Qt::DropAction dropAction = drag->exec();
//Do something
qDebug()<<"Press";
}
}

Adding a QSizeGrip to the corner of a QLabel

I'm attempting to produce a widget that consists of a text display that can be resized by the user grabbing the lower right corner. So far I've been able to generate this:
I've applied a red background to the layout to make it more obvious what's going on. I've used the following code to generate this:
m_sizeGrip = new QSizeGrip( this );
m_layout = new QHBoxLayout( this );
m_label = new QLabel( this );
m_layout->setContentsMargins( QMargins() );
m_layout->setSpacing( 0 );
m_layout->addWidget( m_label );
m_layout->addWidget( m_sizeGrip, 0, Qt::AlignBottom | Qt::AlignRight );
setWindowFlags( Qt::SubWindow );
Basically, it's a horizontal layout with the label and grip added to it, which is then installed on a QWidget. My problem is that I'd like the grip to be on the lower right corner of the label, rather than the parent widget. I'd also like to make it invisible while keeping it enabled.
Or perhaps I'm going about this the wrong way. My ultimate goal is to have a textual display widget that can be resized by the user either horizontally or vertically, but doesn't have a visible grip that would obscure the text. Am I already on the right track with the code above, or is there a better way to achieve this?
You could create a custom QLabel for that. The idea would be to track mouse move events (which by default only fire when a mouse button is pressed), and resize based on how much the mouse traveled since the last event.
This allows you to control exactly how to display the "gripper" (if at all) and what shape it should have. You can constrain the resizing to vertical or horizontal (or not).
Here's a demo of how you could do that (resizes both ways). Warning: this might wreak havoc in your layout.
#include <QtGui>
class GripLabel: public QLabel
{
Q_OBJECT
public:
GripLabel(QString const& title, QWidget* parent = 0)
: QLabel(title, parent),
resizing(false),
gripSize(10, 10)
{
// Prevent the widget from disappearing altogether
// Bare minimum would be gripSize
setMinimumSize(100, 30);
}
QSize sizeHint() const
{
return minimumSize();
}
protected:
bool mouseInGrip(QPoint mousePos)
{
// "handle" is in the lower right hand corner
return ((mousePos.x() > (width() - gripSize.width()))
&& (mousePos.y() > (height() - gripSize.height())));
}
void mousePressEvent(QMouseEvent *e)
{
// Check if we hit the grip handle
if (mouseInGrip(e->pos())) {
oldPos = e->pos();
resizing = true;
} else {
resizing = false;
}
}
void mouseMoveEvent(QMouseEvent *e)
{
if (resizing) {
// adapt the widget size based on mouse movement
QPoint delta = e->pos() - oldPos;
oldPos = e->pos();
setMinimumSize(width()+delta.x(), height()+delta.y());
updateGeometry();
}
}
void paintEvent(QPaintEvent *e)
{
QLabel::paintEvent(e);
QPainter p(this);
p.setPen(Qt::red);
p.drawRect(width()-gripSize.width(), height()-gripSize.height(),
gripSize.width(), gripSize.height());
}
private:
bool resizing;
QSize gripSize;
QPoint oldPos;
};
Sample main:
#include "griplabel.h"
int main(int argc, char **argv)
{
QApplication app(argc, argv);
QWidget *w = new QWidget;
QPushButton *b = new QPushButton("button");
GripLabel *l = new GripLabel("Hello");
QHBoxLayout *y = new QHBoxLayout;
y->addWidget(b);
y->addWidget(l);
y->setSizeConstraint(QLayout::SetFixedSize);
w->setLayout(y);
w->show();
return app.exec();
}

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