延续上一篇文章,本文以另一种方法实现QAbstractScrollArea。此例子是一个图片缩略图的列表控件,控件沿水平方向延伸。仅作为一个例子,因为实际的图片列表可以用QListWidget实现,并不需要自己写代码。下面是程序的运行截图:
头文件:
class MListWidget : public QAbstractScrollArea { Q_OBJECT public: MListWidget(QWidget* parent = 0); void append(const QPixmap& pixmap, const QString& name); int currentItem() const; private: bool eventFilter(QObject* src, QEvent* event) override; bool viewportEvent(QEvent* event) override; void sizeChanged(const QSize &contentSize); private slots: void verticalScrollBarValueChanged(int value); void horizontalScrollBarValueChanged(int value); private: class MImageList; MImageList* lists; }; class MListWidget::MImageList : public QWidget { Q_OBJECT public: MImageList(QWidget* parent = 0); void append(const QPixmap& pixmap, const QString& name); int currentItem() const; private: void paintEvent(QPaintEvent* event) override; void mouseMoveEvent(QMouseEvent* event) override; void mousePressEvent(QMouseEvent* event) override; void mouseReleaseEvent(QMouseEvent* event) override; void enterEvent(QEvent* event) override; void leaveEvent(QEvent* event) override; private: static const QSize imageSize; static const QSize textSize; static const int itemMargin; QVector<QPixmap> images; QStringList texts; QPoint pressPt; int hoverItem; int clickItem; };
CPP文件。代码约200行太长我把它折叠了:
MListWidget::MListWidget(QWidget* parent) : QAbstractScrollArea(parent) { QScrollBar* vbar = verticalScrollBar(); connect(vbar, &QScrollBar::valueChanged, this, &MListWidget::verticalScrollBarValueChanged); QScrollBar* hbar = horizontalScrollBar(); connect(hbar, &QScrollBar::valueChanged, this, &MListWidget::horizontalScrollBarValueChanged); lists = new MImageList(viewport()); lists->installEventFilter(this); } int MListWidget::currentItem() const { return lists->currentItem(); } bool MListWidget::eventFilter(QObject* src, QEvent* event) { if (src == lists && event->type() == QEvent::Resize) { /* 内容Widget的大小变化 */ QResizeEvent* rszEvent = dynamic_cast<QResizeEvent*>(event); sizeChanged(rszEvent->size()); } return QAbstractScrollArea::eventFilter(src, event); } bool MListWidget::viewportEvent(QEvent* event) { if (event->type() == QEvent::Resize) { /* viewport的大小变化 */ sizeChanged(lists->size()); } return QAbstractScrollArea::viewportEvent(event); } void MListWidget::append(const QPixmap& pixmap, const QString& name) { lists->append(pixmap, name); } void MListWidget::verticalScrollBarValueChanged(int value) { lists->move(lists->x(), -value); } void MListWidget::horizontalScrollBarValueChanged(int value) { lists->move(-value, lists->y()); } void MListWidget::sizeChanged(const QSize &contentSize) { QScrollBar* vbar = verticalScrollBar(); vbar->setMinimum(0); vbar->setMaximum(std::max(0, contentSize.height() - viewport()->height())); vbar->setPageStep(viewport()->height()); QScrollBar* hbar = horizontalScrollBar(); hbar->setMinimum(0); hbar->setMaximum(std::max(0, contentSize.width() - viewport()->width())); hbar->setPageStep(viewport()->width()); } ///////////////////////////////////////////////////////////////////////////////////////// const QSize MListWidget::MImageList::imageSize(100, 80); const QSize MListWidget::MImageList::textSize(100, 22); const int MListWidget::MImageList::itemMargin = 6; MListWidget::MImageList::MImageList(QWidget* parent) : QWidget(parent), pressPt(0xDEADBEEF, 0xDEADBEEF) { setMouseTracking(true); hoverItem = -1; clickItem = -1; } void MListWidget::MImageList::append(const QPixmap& pixmap, const QString& name) { images.push_back(pixmap); texts.push_back(name); int count = images.size(); int w = count * (imageSize.width() + 2 * itemMargin); int h = imageSize.height() + textSize.height() + itemMargin; setFixedSize(w, h); update(); } void MListWidget::MImageList::paintEvent(QPaintEvent* event) { QPainter painter(this); for (int i = 0; i < images.size(); i++) { int x = i * (imageSize.width() + 2 * itemMargin) + itemMargin; int y = itemMargin; painter.drawPixmap(QRect(QPoint(x, y), imageSize), images[i]); y += imageSize.height(); painter.drawText(QRect(QPoint(x, y), textSize), Qt::AlignCenter, texts[i]); if (clickItem == i) { int itemx = x - itemMargin; int itemy = 0; int itemw = imageSize.width() + 2 * itemMargin - 1; int itemh = imageSize.height() + textSize.height() + itemMargin - 1; painter.save(); painter.setPen(QColor(97, 142, 229, 97)); painter.setBrush(QColor(97, 172, 249, 97)); painter.drawRect(QRect(itemx, itemy, itemw, itemh)); painter.restore(); } else if (hoverItem == i) { int itemx = x - itemMargin; int itemy = 0; int itemw = imageSize.width() + 2 * itemMargin - 1; int itemh = imageSize.height() + textSize.height() + itemMargin - 1; painter.save(); painter.setPen(QColor(97, 142, 229, 63)); painter.setBrush(QColor(97, 172, 249, 63)); painter.drawRect(QRect(itemx, itemy, itemw, itemh)); painter.restore(); } } } void MListWidget::MImageList::mouseMoveEvent(QMouseEvent* event) { int itemw = imageSize.width() + 2 * itemMargin; int itemh = imageSize.height() + textSize.height(); if (event->pos().y() < itemh) { hoverItem = event->pos().x() / itemw; update(); } } void MListWidget::MImageList::mousePressEvent(QMouseEvent* event) { if (hoverItem >= 0) { pressPt = event->pos(); update(); } } void MListWidget::MImageList::mouseReleaseEvent(QMouseEvent* event) { if ((event->pos() - pressPt).manhattanLength() <= 2) { pressPt = QPoint(0xDEADBEEF, 0xDEADBEEF); clickItem = hoverItem; update(); } } void MListWidget::MImageList::enterEvent(QEvent* event) { // do nothing. } void MListWidget::MImageList::leaveEvent(QEvent* event) { if (hoverItem >= 0) { hoverItem = -1; update(); } } int MListWidget::MImageList::currentItem() const { return clickItem; }View Code
在主窗口添加几个项即可。下方代码中,QtTest是主窗口类,ui.ivSelect是MListWidget类:
QtTest::QtTest(QWidget *parent) : QMainWindow(parent) { ui.setupUi(this); QPixmap myImage(200, 200); myImage.fill(Qt::green); ui.ivSelect->append(myImage, u8"图像1"); ui.ivSelect->append(myImage, u8"图像2"); ui.ivSelect->append(myImage, u8"图像3"); ui.ivSelect->append(myImage, u8"图像4"); ui.ivSelect->append(myImage, u8"图像5"); ui.ivSelect->append(myImage, u8"图像6"); ui.ivSelect->append(myImage, u8"图像7"); ui.ivSelect->append(myImage, u8"图像8"); ui.ivSelect->append(myImage, u8"图像9"); ui.ivSelect->append(myImage, u8"图像A"); }
附:经过查找Qt帮助文档。我发现上方的两个处理滚动条值改变的槽函数是多余的。Qt默认已经响应了滚动条的事件,封装成虚函数QAbstractScrollArea::scrollContentsBy(...)。只需要重写这个虚函数,根据此函数传入的水平垂直偏移增量计算新的显示内容就行了。不用手动连接滚动条的信号。
标签:const,MImageList,自定义,QAbstractScrollArea,void,一个,int,MListWidget,event From: https://www.cnblogs.com/mengxiangdu/p/17919725.html