1
/****************************************************************************
3
** Copyright (C) 1992-2005 Trolltech AS. All rights reserved.
5
** This file is part of the widgets module of the Qt Toolkit.
7
** This file may be distributed under the terms of the Q Public License
8
** as defined by Trolltech AS of Norway and appearing in the file
9
** LICENSE.QPL included in the packaging of this file.
11
** This file may be distributed and/or modified under the terms of the
12
** GNU General Public License version 2 as published by the Free Software
13
** Foundation and appearing in the file LICENSE.GPL included in the
14
** packaging of this file.
16
** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
17
** information about Qt Commercial License Agreements.
18
** See http://www.trolltech.com/qpl/ for QPL licensing information.
19
** See http://www.trolltech.com/gpl/ for GPL licensing information.
21
** Contact info@trolltech.com if any conditions of this licensing are
24
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
25
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27
****************************************************************************/
29
#include "qabstractscrollarea.h"
30
#include "qscrollbar.h"
31
#include "qapplication.h"
33
#include "qstyleoption.h"
36
#include "qabstractscrollarea_p.h"
40
\class QAbstractScrollArea qabstractscrollarea.h
42
\brief The QAbstractScrollArea widget provides a scrolling area with
43
on-demand scroll bars.
45
\ingroup abstractwidgets
47
QAbstractScrollArea is a low-level abstraction of a scrolling area. It gives
48
you full control of the scroll bars, at the cost of simplicity. In
49
most cases, using a QScrollArea is preferable.
51
QAbstractScrollArea's central child widget is the scrolling area itself,
52
called viewport(). The viewport widget uses all available
53
space. Next to the viewport is a vertical scroll bar (accessible
54
with verticalScrollBar()), and below a horizontal scroll bar
55
(accessible with horizontalScrollBar()). Each scroll bar can be
56
either visible or hidden, depending on the scroll bar's policy
57
(see \l verticalScrollBarPolicy and \l horizontalScrollBarPolicy).
58
When a scroll bar is hidden, the viewport expands in order to
59
cover all available space. When a scroll bar becomes visible
60
again, the viewport shrinks in order to make room for the scroll
63
With a scroll bar policy of Qt::ScrollBarAsNeeded (the default),
64
QAbstractScrollArea shows scroll bars when those provide a non-zero
65
scrolling range, and hides them otherwise. You control the range
66
of each scroll bar with QAbstractSlider::setRange().
68
In order to track scroll bar movements, reimplement the virtual
69
function scrollContentsBy(). In order to fine-tune scrolling
70
behavior, connect to a scroll bar's
71
QAbstractSlider::actionTriggered() signal and adjust the \l
72
QAbstractSlider::sliderPosition as you wish.
74
It is possible to reserve a margin area around the viewport, see
75
setViewportMargins(). The feature is mostly used to place a
76
QHeaderView widget above or beside the scrolling area.
78
For convience, QAbstractScrollArea makes all viewport events available in
79
the virtual viewportEvent() handler. QWidget's specialised
80
handlers are remapped to viewport events in the cases where this
81
makes sense. The remapped specialised handlers are: paintEvent(),
82
mousePressEvent(), mouseReleaseEvent(), mouseDoubleClickEvent(),
83
mouseMoveEvent(), wheelEvent(), dragEnterEvent(), dragMoveEvent(),
84
dragLeaveEvent(), dropEvent(), contextMenuEvent(). and
89
inline bool QAbstractScrollAreaPrivate::viewportEvent(QEvent *e)
90
{ Q_Q(QAbstractScrollArea); return q->viewportEvent(e); }
92
class QAbstractScrollAreaHelper : public QWidget
95
QAbstractScrollAreaHelper(QWidget *parent):QWidget(parent){}
96
bool event(QEvent *e);
97
friend class QAbstractScrollArea;
99
bool QAbstractScrollAreaHelper::event(QEvent *e) {
100
if (QAbstractScrollArea* viewport = qobject_cast<QAbstractScrollArea*>(parentWidget()))
101
return ((QAbstractScrollAreaPrivate*)((QAbstractScrollAreaHelper*)viewport)->d_ptr)->viewportEvent(e);
102
return QWidget::event(e);
105
QAbstractScrollAreaPrivate::QAbstractScrollAreaPrivate()
106
:hbar(0), vbar(0), vbarpolicy(Qt::ScrollBarAsNeeded), hbarpolicy(Qt::ScrollBarAsNeeded),
107
viewport(0), left(0), top(0), right(0), bottom(0),
108
xoffset(0), yoffset(0)
113
void QAbstractScrollAreaPrivate::init()
115
Q_Q(QAbstractScrollArea);
116
q->setFocusPolicy(Qt::WheelFocus);
117
q->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken);
118
q->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
119
hbar = new QScrollBar(Qt::Horizontal, q);
120
QObject::connect(hbar, SIGNAL(valueChanged(int)), q, SLOT(hslide(int)));
121
QObject::connect(hbar, SIGNAL(rangeChanged(int,int)), q, SLOT(showOrHideScrollBars()), Qt::QueuedConnection);
122
vbar = new QScrollBar(Qt::Vertical, q);
123
QObject::connect(vbar, SIGNAL(valueChanged(int)), q, SLOT(vslide(int)));
124
QObject::connect(hbar, SIGNAL(rangeChanged(int,int)), q, SLOT(showOrHideScrollBars()), Qt::QueuedConnection);
125
viewport = new QAbstractScrollAreaHelper(q);
126
viewport->setBackgroundRole(QPalette::Base);
127
viewport->setFocusProxy(q);
128
QEvent userEvent(QEvent::User);
129
QApplication::sendEvent(viewport, &userEvent);
132
void QAbstractScrollAreaPrivate::layoutChildren()
134
Q_Q(QAbstractScrollArea);
135
bool needh = (hbarpolicy == Qt::ScrollBarAlwaysOn
136
|| (hbarpolicy == Qt::ScrollBarAsNeeded && hbar->minimum() < hbar->maximum()));
138
bool needv = (vbarpolicy == Qt::ScrollBarAlwaysOn
139
|| (vbarpolicy == Qt::ScrollBarAsNeeded && vbar->minimum() < vbar->maximum()));
141
int hsbExt = hbar->sizeHint().height();
142
int vsbExt = vbar->sizeHint().width();
144
QRect vr = q->rect();
147
if (q->style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents, &opt, q)) {
148
int extra = q->style()->pixelMetric(QStyle::PM_DefaultFrameWidth) * 2;
151
fr.setBottom(fr.bottom() - hsbExt - extra);
152
hbar->setGeometry(QStyle::visualRect(opt.direction, opt.rect, QRect(0, fr.bottom() + 1 + extra, fr.width() - (needv?(vsbExt+extra):0), hsbExt)));
155
fr.setRight(fr.right() - vsbExt - extra);
156
vbar->setGeometry(QStyle::visualRect(opt.direction, opt.rect, QRect(fr.right() + 1 + extra, 0, vsbExt, fr.height())));
158
q->setFrameRect(QStyle::visualRect(opt.direction, opt.rect, fr));
159
vr = q->contentsRect();
162
vr = q->contentsRect();
164
vr.setBottom(vr.bottom() - hsbExt);
165
hbar->setGeometry(QStyle::visualRect(opt.direction, opt.rect, QRect(vr.left(), vr.bottom() + 1, vr.width() - (needv?vsbExt:0), hsbExt)));
168
vr.setRight(vr.right() - vsbExt);
169
vbar->setGeometry(QStyle::visualRect(opt.direction, opt.rect, QRect(vr.right() + 1, vr.top(), vsbExt, vr.height())));
171
vr = QStyle::visualRect(opt.direction, opt.rect, vr);
173
hbar->setVisible(needh);
174
vbar->setVisible(needv);
175
vr.adjust(left, top, -right, -bottom);
176
viewport->setGeometry(vr); // resize the viewport last
182
Creates a new QAbstractScrollAreaPrivate, \a dd with the given \a parent.
184
QAbstractScrollArea::QAbstractScrollArea(QAbstractScrollAreaPrivate &dd, QWidget *parent)
187
Q_D(QAbstractScrollArea);
192
Constructs a viewport.
194
The \a parent arguments is sent to the QWidget constructor.
196
QAbstractScrollArea::QAbstractScrollArea(QWidget *parent)
197
:QFrame(*new QAbstractScrollAreaPrivate, parent)
199
Q_D(QAbstractScrollArea);
205
Destroys the viewport.
207
QAbstractScrollArea::~QAbstractScrollArea()
211
/*! Returns the viewport widget.
213
QWidget *QAbstractScrollArea::viewport() const
215
Q_D(const QAbstractScrollArea);
221
Returns the size of the viewport as if the scroll bars had no valid
224
// ### still thinking about the name
225
QSize QAbstractScrollArea::maximumViewportSize() const
227
Q_D(const QAbstractScrollArea);
228
int hsbExt = d->hbar->sizeHint().height();
229
int vsbExt = d->vbar->sizeHint().width();
231
int f = 2 * d->frameWidth;
232
QSize max = size() - QSize(f,f);
233
if (d->vbarpolicy == Qt::ScrollBarAlwaysOn)
234
max.rwidth() -= vsbExt;
235
if (d->hbarpolicy == Qt::ScrollBarAlwaysOn)
236
max.rheight() -= hsbExt;
241
\property QAbstractScrollArea::verticalScrollBarPolicy
242
\brief the policy for the vertical scroll bar
244
The default policy is \c Qt::ScrollBarAsNeeded.
246
\sa horizontalScrollBarPolicy
249
Qt::ScrollBarPolicy QAbstractScrollArea::verticalScrollBarPolicy() const
251
Q_D(const QAbstractScrollArea);
252
return d->vbarpolicy;
255
void QAbstractScrollArea::setVerticalScrollBarPolicy(Qt::ScrollBarPolicy policy)
257
Q_D(QAbstractScrollArea);
258
d->vbarpolicy = policy;
265
Returns the vertical scroll bar.
267
\sa verticalScrollBarPolicy, horizontalScrollBar()
269
QScrollBar *QAbstractScrollArea::verticalScrollBar() const
271
Q_D(const QAbstractScrollArea);
276
\property QAbstractScrollArea::horizontalScrollBarPolicy
277
\brief the policy for the horizontal scroll bar
279
The default policy is \c Qt::ScrollBarAsNeeded.
281
\sa verticalScrollBarPolicy
284
Qt::ScrollBarPolicy QAbstractScrollArea::horizontalScrollBarPolicy() const
286
Q_D(const QAbstractScrollArea);
287
return d->hbarpolicy;
290
void QAbstractScrollArea::setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy policy)
292
Q_D(QAbstractScrollArea);
293
d->hbarpolicy = policy;
299
Returns the horizontal scroll bar.
301
\sa horizontalScrollBarPolicy, verticalScrollBar()
303
QScrollBar *QAbstractScrollArea::horizontalScrollBar() const
305
Q_D(const QAbstractScrollArea);
310
Sets the margins around the scrolling area to \a left, \a top, \a
311
right and \a bottom. This is useful for applications such as
312
spreadsheets with "locked" rows and columns. The marginal space is
313
is left blank; put widgets in the unused area.
315
By default all margins are zero.
318
void QAbstractScrollArea::setViewportMargins(int left, int top, int right, int bottom)
320
Q_D(QAbstractScrollArea);
329
This is the main event handler for the QAbstractScrollArea widget (\e not
330
the scrolling area viewport()). The event is passed in \a e.
332
bool QAbstractScrollArea::event(QEvent *e)
334
Q_D(QAbstractScrollArea);
336
case QEvent::MouseTrackingChange:
337
d->viewport->setMouseTracking(hasMouseTracking());
343
QFrame::paintEvent((QPaintEvent*)e);
345
case QEvent::ContextMenu:
346
if (static_cast<QContextMenuEvent *>(e)->reason() == QContextMenuEvent::Keyboard)
347
return QFrame::event(e);
350
case QEvent::MouseButtonPress:
351
case QEvent::MouseButtonRelease:
352
case QEvent::MouseButtonDblClick:
353
case QEvent::MouseMove:
355
#ifndef QT_NO_DRAGANDDROP
357
case QEvent::DragEnter:
358
case QEvent::DragMove:
359
case QEvent::DragLeave:
361
case QEvent::StyleChange:
365
return QFrame::event(e);
370
/*! The main event handler for the scrolling area (the viewport()
371
widget). It handles event \a e.
373
You can reimplement this function in a subclass, but we recommend
374
using one of the specialized event handlers instead.
376
Specialised handlers for viewport events are: paintEvent(),
377
mousePressEvent(), mouseReleaseEvent(), mouseDoubleClickEvent(),
378
mouseMoveEvent(), wheelEvent(), dragEnterEvent(), dragMoveEvent(),
379
dragLeaveEvent(), dropEvent(), contextMenuEvent(), and
383
bool QAbstractScrollArea::viewportEvent(QEvent *e)
385
Q_D(QAbstractScrollArea);
389
case QEvent::MouseButtonPress:
390
case QEvent::MouseButtonRelease:
391
case QEvent::MouseButtonDblClick:
392
case QEvent::MouseMove:
393
case QEvent::ContextMenu:
394
#ifndef QT_NO_DRAGANDDROP
396
case QEvent::DragEnter:
397
case QEvent::DragMove:
398
case QEvent::DragLeave:
400
return QFrame::event(e);
402
if (!QFrame::event(e) || !e->isAccepted()) {
403
if (static_cast<QWheelEvent*>(e)->orientation() == Qt::Horizontal)
404
return QApplication::sendEvent(d->hbar, e);
405
return QApplication::sendEvent(d->vbar, e);
410
return static_cast<QAbstractScrollAreaHelper*>(d->viewport)->QWidget::event(e);
414
\fn void QAbstractScrollArea::resizeEvent(QResizeEvent *event)
416
This event handler can be reimplemented in a subclass to receive
417
resize events (passed in \a event), for the viewport() widget.
418
When resizeEvent() is called, the viewport already has its new
419
geometry. The old size is accessible through
420
QResizeEvent::oldSize().
422
\sa QWidget::resizeEvent()
424
void QAbstractScrollArea::resizeEvent(QResizeEvent *)
429
\fn void QAbstractScrollArea::paintEvent(QPaintEvent *event)
431
This event handler can be reimplemented in a subclass to receive
432
paint events (passed in \a event), for the viewport() widget.
434
Note: If you open a painter, make sure to open it on the
437
\sa QWidget::paintEvent()
439
void QAbstractScrollArea::paintEvent(QPaintEvent*)
444
This event handler can be reimplemented in a subclass to receive
445
mouse press events for the viewport() widget. The event is passed
448
\sa QWidget::mousePressEvent()
450
void QAbstractScrollArea::mousePressEvent(QMouseEvent *e)
456
This event handler can be reimplemented in a subclass to receive
457
mouse release events for the viewport() widget. The event is
460
\sa QWidget::mouseReleaseEvent()
462
void QAbstractScrollArea::mouseReleaseEvent(QMouseEvent *e)
468
This event handler can be reimplemented in a subclass to receive
469
mouse double click events for the viewport() widget. The event is
472
\sa QWidget::mouseDoubleClickEvent()
474
void QAbstractScrollArea::mouseDoubleClickEvent(QMouseEvent *e)
480
This event handler can be reimplemented in a subclass to receive
481
mouse move events for the viewport() widget. The event is passed
484
\sa QWidget::mouseMoveEvent()
486
void QAbstractScrollArea::mouseMoveEvent(QMouseEvent *e)
492
This event handler can be reimplemented in a subclass to receive
493
wheel events for the viewport() widget. The event is passed in \a
496
\sa QWidget::wheelEvent()
498
#ifndef QT_NO_WHEELEVENT
499
void QAbstractScrollArea::wheelEvent(QWheelEvent *e)
506
This event handler can be reimplemented in a subclass to receive
507
context menu events for the viewport() widget. The event is passed
510
\sa QWidget::contextMenuEvent()
512
void QAbstractScrollArea::contextMenuEvent(QContextMenuEvent *e)
518
This function is called with key event \a e when key presses
519
occur. It handles PageUp, PageDown, Up, Down, Left, and Right, and
520
ignores all other key presses.
522
void QAbstractScrollArea::keyPressEvent(QKeyEvent * e)
524
Q_D(QAbstractScrollArea);
527
d->vbar->triggerAction(QScrollBar::SliderPageStepSub);
529
case Qt::Key_PageDown:
530
d->vbar->triggerAction(QScrollBar::SliderPageStepAdd);
533
d->vbar->triggerAction(QScrollBar::SliderSingleStepSub);
536
d->vbar->triggerAction(QScrollBar::SliderSingleStepAdd);
539
d->hbar->triggerAction(QScrollBar::SliderSingleStepSub);
542
d->hbar->triggerAction(QScrollBar::SliderSingleStepAdd);
552
#ifndef QT_NO_DRAGANDDROP
554
\fn void QAbstractScrollArea::dragEnterEvent(QDragEnterEvent *event)
556
This event handler can be reimplemented in a subclass to receive
557
drag enter events (passed in \a event), for the viewport() widget.
559
\sa QWidget::dragEnterEvent()
561
void QAbstractScrollArea::dragEnterEvent(QDragEnterEvent *)
566
\fn void QAbstractScrollArea::dragMoveEvent(QDragMoveEvent *event)
568
This event handler can be reimplemented in a subclass to receive
569
drag move events (passed in \a event), for the viewport() widget.
571
\sa QWidget::dragMoveEvent()
573
void QAbstractScrollArea::dragMoveEvent(QDragMoveEvent *)
578
\fn void QAbstractScrollArea::dragLeaveEvent(QDragLeaveEvent *event)
580
This event handler can be reimplemented in a subclass to receive
581
drag leave events (passed in \a event), for the viewport() widget.
583
\sa QWidget::dragLeaveEvent()
585
void QAbstractScrollArea::dragLeaveEvent(QDragLeaveEvent *)
590
\fn void QAbstractScrollArea::dropEvent(QDropEvent *event)
592
This event handler can be reimplemented in a subclass to receive
593
drop events (passed in \a event), for the viewport() widget.
595
\sa QWidget::dropEvent()
597
void QAbstractScrollArea::dropEvent(QDropEvent *)
605
Scrolls the viewport's contents by \a dx, \a dy.
607
void QAbstractScrollArea::scrollContentsBy(int, int)
609
viewport()->update();
612
void QAbstractScrollAreaPrivate::hslide(int x)
614
Q_Q(QAbstractScrollArea);
615
int dx = xoffset - x;
617
q->scrollContentsBy(dx, 0);
620
void QAbstractScrollAreaPrivate::vslide(int y)
622
Q_Q(QAbstractScrollArea);
623
int dy = yoffset - y;
625
q->scrollContentsBy(0, dy);
628
void QAbstractScrollAreaPrivate::showOrHideScrollBars()
637
QSize QAbstractScrollArea::minimumSizeHint() const
639
Q_D(const QAbstractScrollArea);
640
int hsbExt = d->hbar->sizeHint().height();
641
int vsbExt = d->vbar->sizeHint().width();
642
int f = 2 * d->frameWidth;
643
return QSize(3*vsbExt + f, 3*hsbExt + f);
649
QSize QAbstractScrollArea::sizeHint() const
651
return QSize(256, 192);
653
Q_D(const QAbstractScrollArea);
654
int h = qMax(10, fontMetrics().height());
655
int f = 2 * d->frameWidth;
656
return QSize((6 * h) + f, (4 * h) + f);
660
#include "moc_qabstractscrollarea.cpp"