PDA

View Full Version : Conceptual Question; QLabel as Banner?



SneakyPeterson
24th June 2010, 14:31
This is more of a conceptual question, so I don't have code to post yet. I am a little bit stuck on thinking of the right way to implement this idea, and I was wondering if anyone could offer an idea.

The Problem: I currently have a custom implementation of a linear layout, where widgets are being placed
from left to right horizontally. When row space runs out, they are moved down to the next row, like so:

1 2 3 4
5 6 7 8
9

The widgets that I am placing each belong to groups that can be arbitrarily long. I am currently trying to design a banner that would be place on top of these object, so if widgets 1,2,3 are in group A, and 4,5.6 are in group B there would be a banner over them like:

[ A ] [
1 2 3 4
B ]
5 6

I thought that QLabel would be the easiest way to do this, but if I run into the case where a group is split into the next row like above, I'm not sure how I can gracefully split the text inside of the label between rows :/. I was wondering if there was an easier way that I'm not thinking of or if I should just try to make this "split a QLabel's text into two different QLabels" idea work.

Cheers,
sp

tbscope
24th June 2010, 18:10
It's not really clear to me what you mean with a banner?
Do you want some column descriptions?

example:



[ItemBanner1Group1] [ItemBanner2Group1] [ItemBanner3Group1]
item 1 item 2 item 3
[ItemBanner3Group1]
item 4
[ItemBanner1Group2] [ItemBanner2Group2]
item 1 item 2


where everything between [ ] is a banner, and the item is underneath the banner

SneakyPeterson
25th June 2010, 09:58
Thanks for the interest. I hope this does a better job of explaining what I'm going for:

The banner acts as a label that is spread across a set of grouped items. So if items 1-3 are in group one, and items 4-6 are in group two, each
group has its own "banner" with text that would say something like "group 1". I was thinking of making a QLabel that would have the same width
as the sum of the 3 items and placing the label on top of all the grouped items, but I wasn't sure if this would be a good idea, since if a group is
split the label must carry on to a new row.

[Text describing group one] [Text de
[Item 1] [item 2] [item 3] ] [Item 4]

scribing group two]
[item 5] [item 6]

Talei
25th June 2010, 11:47
If I understand correctly what You need is QGroupBox.

tbscope
25th June 2010, 16:50
I gave it a try, check out the code below.
It's absolutely not perfect. In fact, I think the most correct way to do this is to create a QLayout subclass.

Screenshot attached below

Edit:
It works by keeping a list of groups and items.
First clear the layout from any widget or layout item.
Then go through each group.
In each group, add all the items to the layout, keeping below the maximum amount of columns
Then, when every item of a group is added add labels, keeping an eye on the span of the items for this group in the rows.

It might not be exactly like you want, but I think you can take it from here :-)

Header


#ifndef SPECIALLAYOUT_H
#define SPECIALLAYOUT_H

#include <QGridLayout>
#include <QStringList>
#include <QString>
#include <QMultiMap>
#include <QWidget>

class SpecialLayout : public QGridLayout
{
Q_OBJECT
public:
explicit SpecialLayout(QWidget *parent = 0);

void addGroup(const QString &groupName);
void addItemWidget(const QString &inGroup);

void setMaximumColumns(int columns);

QStringList groupNames() const;

signals:

public slots:

protected:
void rebuildLayout();

private:
QStringList m_groupNames;
QMultiMap<QString, QString> m_groupWidgetMap;
int m_maximumColumnCount;
};

#endif // SPECIALLAYOUT_H


Implementation


#include "speciallayout.h"

#include <QLabel>
#include <QSpacerItem>
#include <QSizePolicy>

SpecialLayout::SpecialLayout(QWidget *parent) :
QGridLayout(parent)
{
m_maximumColumnCount = 10;
}

void SpecialLayout::addGroup(const QString &groupName)
{
if (m_groupNames.contains(groupName))
return;

m_groupNames.append(groupName);
}

void SpecialLayout::addItemWidget(const QString &inGroup)
{
if (!m_groupNames.contains(inGroup))
return;

m_groupWidgetMap.insert(inGroup, "Item");

rebuildLayout();
}

QStringList SpecialLayout::groupNames() const
{
return m_groupNames;
}

void SpecialLayout::setMaximumColumns(int columns)
{
m_maximumColumnCount = columns;
}

void SpecialLayout::rebuildLayout()
{
QLayoutItem *item;
while ((item = takeAt(0))) {
if (item->widget())
delete item->widget();

delete item;
}

int currentColumn = 0;
int currentRow = 0;
int widgetColumn = 0;
int widgetRow = 0;
int columnCount = 0;

foreach(QString group, m_groupNames) {

if (!m_groupWidgetMap.values(group).isEmpty()) {

widgetColumn = currentColumn;
widgetRow = currentRow;

foreach(QString string, m_groupWidgetMap.values(group)) {
QLabel *itemWidget = new QLabel("<b>" + string + "</b>");
addWidget(itemWidget, widgetRow + 1, widgetColumn);

++widgetColumn;

if (widgetColumn > m_maximumColumnCount - 1) {
widgetColumn = 0;
widgetRow += 2;
}
}

columnCount = m_groupWidgetMap.values(group).count();

int columnSpan;

while (columnCount > 0) {
columnSpan = qMin(m_maximumColumnCount - currentColumn, columnCount);

QLabel *label = new QLabel(group);

addWidget(label, currentRow, currentColumn, 1, columnSpan);

columnCount -= columnSpan;
currentColumn += columnSpan;
if (currentColumn > m_maximumColumnCount - 1) {
currentColumn = 0;
currentRow += 2;
}
}
}
}
}

SneakyPeterson
28th June 2010, 08:18
I gave it a try, check out the code below.
It's absolutely not perfect. In fact, I think the most correct way to do this is to create a QLayout subclass.

Screenshot attached below

Edit:
It works by keeping a list of groups and items.
First clear the layout from any widget or layout item.
Then go through each group.
In each group, add all the items to the layout, keeping below the maximum amount of columns
Then, when every item of a group is added add labels, keeping an eye on the span of the items for this group in the rows.

It might not be exactly like you want, but I think you can take it from here :-)

Header


#ifndef SPECIALLAYOUT_H
#define SPECIALLAYOUT_H

#include <QGridLayout>
#include <QStringList>
#include <QString>
#include <QMultiMap>
#include <QWidget>

class SpecialLayout : public QGridLayout
{
Q_OBJECT
public:
explicit SpecialLayout(QWidget *parent = 0);

void addGroup(const QString &groupName);
void addItemWidget(const QString &inGroup);

void setMaximumColumns(int columns);

QStringList groupNames() const;

signals:

public slots:

protected:
void rebuildLayout();

private:
QStringList m_groupNames;
QMultiMap<QString, QString> m_groupWidgetMap;
int m_maximumColumnCount;
};

#endif // SPECIALLAYOUT_H


Implementation


#include "speciallayout.h"

#include <QLabel>
#include <QSpacerItem>
#include <QSizePolicy>

SpecialLayout::SpecialLayout(QWidget *parent) :
QGridLayout(parent)
{
m_maximumColumnCount = 10;
}

void SpecialLayout::addGroup(const QString &groupName)
{
if (m_groupNames.contains(groupName))
return;

m_groupNames.append(groupName);
}

void SpecialLayout::addItemWidget(const QString &inGroup)
{
if (!m_groupNames.contains(inGroup))
return;

m_groupWidgetMap.insert(inGroup, "Item");

rebuildLayout();
}

QStringList SpecialLayout::groupNames() const
{
return m_groupNames;
}

void SpecialLayout::setMaximumColumns(int columns)
{
m_maximumColumnCount = columns;
}

void SpecialLayout::rebuildLayout()
{
QLayoutItem *item;
while ((item = takeAt(0))) {
if (item->widget())
delete item->widget();

delete item;
}

int currentColumn = 0;
int currentRow = 0;
int widgetColumn = 0;
int widgetRow = 0;
int columnCount = 0;

foreach(QString group, m_groupNames) {

if (!m_groupWidgetMap.values(group).isEmpty()) {

widgetColumn = currentColumn;
widgetRow = currentRow;

foreach(QString string, m_groupWidgetMap.values(group)) {
QLabel *itemWidget = new QLabel("<b>" + string + "</b>");
addWidget(itemWidget, widgetRow + 1, widgetColumn);

++widgetColumn;

if (widgetColumn > m_maximumColumnCount - 1) {
widgetColumn = 0;
widgetRow += 2;
}
}

columnCount = m_groupWidgetMap.values(group).count();

int columnSpan;

while (columnCount > 0) {
columnSpan = qMin(m_maximumColumnCount - currentColumn, columnCount);

QLabel *label = new QLabel(group);

addWidget(label, currentRow, currentColumn, 1, columnSpan);

columnCount -= columnSpan;
currentColumn += columnSpan;
if (currentColumn > m_maximumColumnCount - 1) {
currentColumn = 0;
currentRow += 2;
}
}
}
}
}



This is very close to what I was going for. Thank you very much for the help!

Cheers,
sp