作为 TabWidget 的可滚动视图
Scrollable view as TabWidget
这是我的问题,我使用 setGeometry()
方法手动显示按钮和标签。
继承自QWidget的MyClass
这是我的代码:
void MyClass::function() {
QLabel *imgP;
QLabel *name;
QPushButton *newConv;
QPixmap *profilPic;
std::stringstream ss;
int j = 0;
int i = 0;
for (int tmp = 0; tmp < 15; tmp++)
{
if (i % 7 == 0 && i != 0)
{
i = 0;
j++;
}
ss << "Username " << tmp;
name = new QLabel(tr(ss.str().c_str()), this);
name->setAlignment(Qt::AlignCenter);
name->setGeometry((30 * (i + 1) + 240 * i), (30 + 390 * j),
240, 60);
profilPic = new QPixmap("./gui/img/avatar1.png");
imgP = new QLabel(this);
imgP->setPixmap(profilPic->scaled(240, 240));
imgP->setGeometry((30 * (i + 1) + 240 * i), (90 + 390 * j),
240, 240);
newConv = new QPushButton(tr("Chat"), this);
newConv->setGeometry((30 * (i + 1) + 240 * i), (330 + 390 * j),
240, 60);
newConv->setFocusPolicy(Qt::NoFocus);
connect(newConv, SIGNAL(released()), this, SLOT(addTab()));
ss.str("");
ss.clear();
i++;
}
}
它可能比它应该的要复杂一点,但它的工作方式正是我想要的..
看起来像这样:
如你所见,效果不错,显示了我的联系人,但是第15个元素被隐藏了,因为window太小了。所以我的问题是:
发生这种情况时如何制作 ScrollView?
我已经知道 QScrollArea
,但我必须使用 QBoxLayout
,我认为这不会完成工作。
感谢您的帮助!
编辑
这是我的 MainWidget class,它显示 window :
class QTabBar;
MainWidget::MainWidget(QWidget *parent) : QWidget(parent)
{
setFixedSize(1920, 1200);
setWindowTitle(tr("Babel"));
QVBoxLayout *mainLayout = new QVBoxLayout;
QTabBar *tb;
UiContact *contact = new UiContact(this);
QScrollArea *contactScrollArea = new QScrollArea();
contactScrollArea->setWidget(contact);
_tabWidget = new QTabWidget;
tb = _tabWidget->tabBar();
_tabWidget->addTab(new Home(), tr("Home"));
_tabWidget->addTab(contactScrollArea, tr("Contact"));
std::ostringstream oss;
_tabWidget->setTabsClosable(true);
connect(_tabWidget, SIGNAL(tabCloseRequested(int)), this, SLOT(closeTab(int)));
tb->tabButton(0, QTabBar::RightSide)->hide();
tb->tabButton(1, QTabBar::RightSide)->hide();
_tabWidget->setFocusPolicy(Qt::NoFocus);
mainLayout->addWidget(_tabWidget);
setLayout(mainLayout);
}
QScrollArea
肯定是要走的路。没有必要使用布局,只需要强制小部件达到它需要的大小。 QScrollArea
可以处理任何 QWidget
派生的 class,并且它将根据需要显示其滚动条。
实际上:如果您可以计算出您需要多少 space(我认为您可以做到),并相应地设置包含小部件的大小限制,QScrollArea 将自动显示滚动条。您可以为此目的使用 QWidget::setMinimumSize
,一个简单的 setMinimumSize(itemWidth*7,itemHeight*(count%7))
就足够了。
此方法确实允许小部件增长到填满 QScrollArea
。此外,如果愿意,可以禁用 QScrollArea
周围的框架。
编辑:
你可能有这样的事情:
MyClass *myClass = new MyClass();
...
tabs->insertTab(1,myClass,"Contact");
在这种情况下的示例实现是:
MyClass *myClass = new MyClass();
...
QScrollArea* contactScrollArea = new QScrollArea();
contactScrollArea->setWidget(myClass);
tabs->insertTab(1,contactScrollArea,"Contact");
它将在选项卡小部件内放置一个滚动区域,并将 MyClass 的实例放入其中
一个QScrollArea
作为比较高的容器class。将 QScrollArea
想象成一个可以在其中嵌入另一个小部件的小部件。默认情况下,它会创建一个空的小部件,可以获取布局。但是通过使用 setWidget
,你可以在其中放置任何你想要的东西。可能的 "combination" 是 QLabel
带有较大的许可文本或任何其他可能变得过大的小部件(例如您的小部件)。
现在,只是一些额外的信息:
当您自己绘制内容(不是创建多个小部件和编写自己的布局内容)时,您可以使用 QAbstractScrollArea
。它会给你完全的控制权。它提供滚动条和一个单独的中间小部件,您可以在 paintEvent
期间向其绘制。但我认为这超出了本文的范围。
现在,为了干净的编码。我实际上建议您创建一个单独的 class ContactItem
。它将由标签、图像和按钮组成,用 QVBoxLayout
组合在一起(这使得它们整齐地排列在彼此之上)。这个"item"可以放在一个QGridLayout
里面。这样,您就无需费心安排物品。如果您在图片上设置最小尺寸,它会确保这些项目是您的首选 width/height。标签大小限制确保字体差异不会影响演示(按钮也是如此)。最后但同样重要的是,您的列表突然可以调整大小。 (通过使用 setRowStretch
和 setColumnStretch
,您可以确保您的列表居中或顶部对齐,以防 window 大于您的列表占用的空间。
函数解释
这里我有一个可能的实现(它不是我最好的代码)从我从屏幕截图和给定的代码中得到的。
它由一个负责选项卡布局的'Widget'组成:
mainwidget.h
#include <QWidget>
#include "uicontact.h"
class QTabWidget;
class MainWidget : public QWidget
{
Q_OBJECT
QTabWidget *_tabWidget;
public:
MainWidget(QWidget *parent = 0);
~MainWidget();
public slots:
void addChatTab();
};
mainwidget.cpp
#include "mainwidget.h"
#include <QScrollArea>
#include <QTabWidget>
#include <QTabBar>
#include <QVBoxLayout>
#include "home.h"
MainWidget::MainWidget(QWidget *parent)
: QWidget(parent)
{
setFixedSize(1920,1200);
setWindowTitle(tr("Babel"));
QVBoxLayout *mainLayout = new QVBoxLayout;
QTabBar *tb;
UiContact *contact = new UiContact(this);
QScrollArea *contactScrollArea = new QScrollArea();
contactScrollArea->setWidget(contact);
_tabWidget = new QTabWidget;
tb = _tabWidget->tabBar();
_tabWidget->addTab(new Home(), tr("Home"));
_tabWidget->addTab(contactScrollArea, tr("Contact"));
_tabWidget->setTabsClosable(true);
connect(_tabWidget, SIGNAL(tabCloseRequested(int)), this, SLOT(closeTab(int)));
tb->tabButton(0, QTabBar::RightSide)->hide();
tb->tabButton(1, QTabBar::RightSide)->hide();
_tabWidget->setFocusPolicy(Qt::NoFocus);
mainLayout->addWidget(_tabWidget);
setLayout(mainLayout);
}
MainWidget::~MainWidget()
{
}
void MainWidget::addChatTab()
{
_tabWidget->addTab(new QWidget, tr("Number %1").arg(_tabWidget->count()-2));
}
class MyClass
负责创建 'contact' 选项卡:
uicontact.cpp
#include "uicontact.h"
#include "mainwidget.h"
#include <QLabel>
#include <QPushButton>
UiContact::UiContact(MainWidget *owner,QWidget *parent) : QWidget(parent)
{
QLabel *imgP;
QLabel *name;
QPushButton *newConv;
QPixmap *profilPic;
int j = 0;
int i = 0;
for (int tmp = 0; tmp < 15; tmp++)
{
if (i % 7 == 0 && i != 0)
{
i = 0;
j++;
}
name = new QLabel(tr("Username %1").arg(tmp), this);
name->setAlignment(Qt::AlignCenter);
name->setGeometry((30 * (i + 1) + 240 * i), (30 + 390 * j),
240, 60);
profilPic = new QPixmap("./gui/img/avatar1.png");
imgP = new QLabel(this);
imgP->setPixmap(profilPic->scaled(240, 240));
imgP->setGeometry((30 * (i + 1) + 240 * i), (90 + 390 * j),
240, 240);
newConv = new QPushButton(tr("Chat"), this);
newConv->setGeometry((30 * (i + 1) + 240 * i), (330 + 390 * j),
240, 60);
newConv->setFocusPolicy(Qt::NoFocus);
connect(newConv, SIGNAL(clicked(bool)), owner, SLOT(addChatTab()));
i++;
}
setMinimumSize(270*7,420*(15/7+1));
}
uicontact.h
文件非常琐碎,因此省略。
需要注意的几件事:MyClass
收到一个 'owner' 指针,这允许它直接与负责添加选项卡的顶级小部件对话。可能您想查看 QSignalMapper
以便能够将单个 QPushButton
映射到一个更已知的值。使用 QSignalMapper
,您可以将按钮映射到整数、字符串、QWidget*
或 QObject*
。
另请注意 tr("Contact %1").arg(tmp)
,这是让您的程序区域设置感知的正确方法。
这是我的问题,我使用 setGeometry()
方法手动显示按钮和标签。
继承自QWidget的MyClass
这是我的代码:
void MyClass::function() {
QLabel *imgP;
QLabel *name;
QPushButton *newConv;
QPixmap *profilPic;
std::stringstream ss;
int j = 0;
int i = 0;
for (int tmp = 0; tmp < 15; tmp++)
{
if (i % 7 == 0 && i != 0)
{
i = 0;
j++;
}
ss << "Username " << tmp;
name = new QLabel(tr(ss.str().c_str()), this);
name->setAlignment(Qt::AlignCenter);
name->setGeometry((30 * (i + 1) + 240 * i), (30 + 390 * j),
240, 60);
profilPic = new QPixmap("./gui/img/avatar1.png");
imgP = new QLabel(this);
imgP->setPixmap(profilPic->scaled(240, 240));
imgP->setGeometry((30 * (i + 1) + 240 * i), (90 + 390 * j),
240, 240);
newConv = new QPushButton(tr("Chat"), this);
newConv->setGeometry((30 * (i + 1) + 240 * i), (330 + 390 * j),
240, 60);
newConv->setFocusPolicy(Qt::NoFocus);
connect(newConv, SIGNAL(released()), this, SLOT(addTab()));
ss.str("");
ss.clear();
i++;
}
}
它可能比它应该的要复杂一点,但它的工作方式正是我想要的..
看起来像这样:
如你所见,效果不错,显示了我的联系人,但是第15个元素被隐藏了,因为window太小了。所以我的问题是:
发生这种情况时如何制作 ScrollView?
我已经知道 QScrollArea
,但我必须使用 QBoxLayout
,我认为这不会完成工作。
感谢您的帮助!
编辑
这是我的 MainWidget class,它显示 window :
class QTabBar;
MainWidget::MainWidget(QWidget *parent) : QWidget(parent)
{
setFixedSize(1920, 1200);
setWindowTitle(tr("Babel"));
QVBoxLayout *mainLayout = new QVBoxLayout;
QTabBar *tb;
UiContact *contact = new UiContact(this);
QScrollArea *contactScrollArea = new QScrollArea();
contactScrollArea->setWidget(contact);
_tabWidget = new QTabWidget;
tb = _tabWidget->tabBar();
_tabWidget->addTab(new Home(), tr("Home"));
_tabWidget->addTab(contactScrollArea, tr("Contact"));
std::ostringstream oss;
_tabWidget->setTabsClosable(true);
connect(_tabWidget, SIGNAL(tabCloseRequested(int)), this, SLOT(closeTab(int)));
tb->tabButton(0, QTabBar::RightSide)->hide();
tb->tabButton(1, QTabBar::RightSide)->hide();
_tabWidget->setFocusPolicy(Qt::NoFocus);
mainLayout->addWidget(_tabWidget);
setLayout(mainLayout);
}
QScrollArea
肯定是要走的路。没有必要使用布局,只需要强制小部件达到它需要的大小。 QScrollArea
可以处理任何 QWidget
派生的 class,并且它将根据需要显示其滚动条。
实际上:如果您可以计算出您需要多少 space(我认为您可以做到),并相应地设置包含小部件的大小限制,QScrollArea 将自动显示滚动条。您可以为此目的使用 QWidget::setMinimumSize
,一个简单的 setMinimumSize(itemWidth*7,itemHeight*(count%7))
就足够了。
此方法确实允许小部件增长到填满 QScrollArea
。此外,如果愿意,可以禁用 QScrollArea
周围的框架。
编辑:
你可能有这样的事情:
MyClass *myClass = new MyClass();
...
tabs->insertTab(1,myClass,"Contact");
在这种情况下的示例实现是:
MyClass *myClass = new MyClass();
...
QScrollArea* contactScrollArea = new QScrollArea();
contactScrollArea->setWidget(myClass);
tabs->insertTab(1,contactScrollArea,"Contact");
它将在选项卡小部件内放置一个滚动区域,并将 MyClass 的实例放入其中
一个QScrollArea
作为比较高的容器class。将 QScrollArea
想象成一个可以在其中嵌入另一个小部件的小部件。默认情况下,它会创建一个空的小部件,可以获取布局。但是通过使用 setWidget
,你可以在其中放置任何你想要的东西。可能的 "combination" 是 QLabel
带有较大的许可文本或任何其他可能变得过大的小部件(例如您的小部件)。
现在,只是一些额外的信息:
当您自己绘制内容(不是创建多个小部件和编写自己的布局内容)时,您可以使用 QAbstractScrollArea
。它会给你完全的控制权。它提供滚动条和一个单独的中间小部件,您可以在 paintEvent
期间向其绘制。但我认为这超出了本文的范围。
现在,为了干净的编码。我实际上建议您创建一个单独的 class ContactItem
。它将由标签、图像和按钮组成,用 QVBoxLayout
组合在一起(这使得它们整齐地排列在彼此之上)。这个"item"可以放在一个QGridLayout
里面。这样,您就无需费心安排物品。如果您在图片上设置最小尺寸,它会确保这些项目是您的首选 width/height。标签大小限制确保字体差异不会影响演示(按钮也是如此)。最后但同样重要的是,您的列表突然可以调整大小。 (通过使用 setRowStretch
和 setColumnStretch
,您可以确保您的列表居中或顶部对齐,以防 window 大于您的列表占用的空间。
函数解释
这里我有一个可能的实现(它不是我最好的代码)从我从屏幕截图和给定的代码中得到的。
它由一个负责选项卡布局的'Widget'组成:
mainwidget.h
#include <QWidget>
#include "uicontact.h"
class QTabWidget;
class MainWidget : public QWidget
{
Q_OBJECT
QTabWidget *_tabWidget;
public:
MainWidget(QWidget *parent = 0);
~MainWidget();
public slots:
void addChatTab();
};
mainwidget.cpp
#include "mainwidget.h"
#include <QScrollArea>
#include <QTabWidget>
#include <QTabBar>
#include <QVBoxLayout>
#include "home.h"
MainWidget::MainWidget(QWidget *parent)
: QWidget(parent)
{
setFixedSize(1920,1200);
setWindowTitle(tr("Babel"));
QVBoxLayout *mainLayout = new QVBoxLayout;
QTabBar *tb;
UiContact *contact = new UiContact(this);
QScrollArea *contactScrollArea = new QScrollArea();
contactScrollArea->setWidget(contact);
_tabWidget = new QTabWidget;
tb = _tabWidget->tabBar();
_tabWidget->addTab(new Home(), tr("Home"));
_tabWidget->addTab(contactScrollArea, tr("Contact"));
_tabWidget->setTabsClosable(true);
connect(_tabWidget, SIGNAL(tabCloseRequested(int)), this, SLOT(closeTab(int)));
tb->tabButton(0, QTabBar::RightSide)->hide();
tb->tabButton(1, QTabBar::RightSide)->hide();
_tabWidget->setFocusPolicy(Qt::NoFocus);
mainLayout->addWidget(_tabWidget);
setLayout(mainLayout);
}
MainWidget::~MainWidget()
{
}
void MainWidget::addChatTab()
{
_tabWidget->addTab(new QWidget, tr("Number %1").arg(_tabWidget->count()-2));
}
class MyClass
负责创建 'contact' 选项卡:
uicontact.cpp
#include "uicontact.h"
#include "mainwidget.h"
#include <QLabel>
#include <QPushButton>
UiContact::UiContact(MainWidget *owner,QWidget *parent) : QWidget(parent)
{
QLabel *imgP;
QLabel *name;
QPushButton *newConv;
QPixmap *profilPic;
int j = 0;
int i = 0;
for (int tmp = 0; tmp < 15; tmp++)
{
if (i % 7 == 0 && i != 0)
{
i = 0;
j++;
}
name = new QLabel(tr("Username %1").arg(tmp), this);
name->setAlignment(Qt::AlignCenter);
name->setGeometry((30 * (i + 1) + 240 * i), (30 + 390 * j),
240, 60);
profilPic = new QPixmap("./gui/img/avatar1.png");
imgP = new QLabel(this);
imgP->setPixmap(profilPic->scaled(240, 240));
imgP->setGeometry((30 * (i + 1) + 240 * i), (90 + 390 * j),
240, 240);
newConv = new QPushButton(tr("Chat"), this);
newConv->setGeometry((30 * (i + 1) + 240 * i), (330 + 390 * j),
240, 60);
newConv->setFocusPolicy(Qt::NoFocus);
connect(newConv, SIGNAL(clicked(bool)), owner, SLOT(addChatTab()));
i++;
}
setMinimumSize(270*7,420*(15/7+1));
}
uicontact.h
文件非常琐碎,因此省略。
需要注意的几件事:MyClass
收到一个 'owner' 指针,这允许它直接与负责添加选项卡的顶级小部件对话。可能您想查看 QSignalMapper
以便能够将单个 QPushButton
映射到一个更已知的值。使用 QSignalMapper
,您可以将按钮映射到整数、字符串、QWidget*
或 QObject*
。
另请注意 tr("Contact %1").arg(tmp)
,这是让您的程序区域设置感知的正确方法。