PDA

View Full Version : QTableWidget NW corner header item?



McKee
26th March 2007, 04:46
Embarassing to ask, but how would I access the top left corner header item in a QTableWidget that has both a horizontal and a vertical header? This is the header item they have in common. I can use


QTableWidget::setHorizontalHeaderLabels ( const QStringList & labels )
and

QTableWidget::setVerticalHeaderLabels ( const QStringList & labels )

but they don't seem to provide access to the item at the corner. Nor do


QTableWidgetItem * QTableWidget::horizontalHeaderItem ( int column ) const
and

QTableWidgetItem * QTableWidget::verticalHeaderItem ( int row) const

Perhaps accessing a header itself via


QHeaderView * QTableView::horizontalHeader () const
or

QHeaderView * QTableView::verticalHeader () const

but then what to do with it?

thanks!

jpn
27th March 2007, 10:19
What would you like to do with it? It's not a header item actually but a button (for more information, see QTableCornerButton at the beginning of src/gui/itemviews/qtableview.cpp).

McKee
30th March 2007, 03:18
I'd like to set its text; that's all.

I see the code you pointed me to -- thanks. QTableView's private cornerWidget member is the QTableCornerButton, and it oddly hides another member of the same name down the inheritance chain, namely QAbstractScrollArea::cornerWidget. Only the latter is exposed via the method cornerWidget(). Doh. QTableWidget::cornerWidget() returns not the QTableCornerButton instance, but QAbstractScrollArea::cornerWidget, which is understandably NULL. Wish there was a QTableView::cornerButton() method.

jpn
30th March 2007, 07:56
It's still possible with some rather ugly "hacking". One would need to use for example QObject::findChild() to get access to the private corner button. An event filter is required for "overriding" the button's paintEvent() (QTableCornerButton::paintEvent() doesn't paint the text even if the button had text set). I have attached an example.

This is, of course, not recommended way for doing it. It is a private button and may be a subject to change in the future. I suggest sending a suggestion about the issue to the Task-Tracker (http://www.trolltech.com/developer/task-tracker).

McKee
30th March 2007, 15:30
Wow! Nice work. Thanks for the example code.

Another way to solve the problem is to just create a new leftmost column, for which I can set the text of the top header item. I was hoping to avoid that because my table works better with my leftmost data in the vertical header items. But it's do-able.

I'll look into the TaskTracker suggestion.

McKee

jtaylor108
23rd July 2007, 04:22
Does anyone know if there is there any way to format the NW corner button using a stylesheet? Setting the following style sheet on the NW corner button in my CTableWidget constructor doesn't seem to do anything:



CTableWidget::CTableWidget( QWidget* parent ):
QTableWidget( parent )
{
QList< QAbstractButton* > buttons = qFindChildren< QAbstractButton* >( this );
for ( int i=0; i<buttons.size(); ++i )
{
buttons[i]->setStyleSheet( "QWidget{ background-color:red; }" );
}
}


I can paint the button myself using an event filter, but it doesn't seem like an end user can modify the appearance.

TIA,

jt

binaural
31st May 2010, 14:04
Hi,

post code from jtaylor108 seems to work for set backgroud color. Anyway I try to change a text of top left corner but it's not changed.
I use same code but instead setStyleSheet I used setText() but text was not set. I s there any other option how to do this? Thanks

danblanks
3rd March 2011, 23:44
This thread has been *very* useful, so I will add some points.

First, you can indeed use a setStyleSheet call in your table widget class to change the corner button border and background as follows:


setStyleSheet("QTableCornerButton::section {border: 2px outset red; background: green;}");

I did not need this functionality for what I wanted to do, but it is still a useful trick to know.

What I wanted to do was place an icon in the corner button to indicate that there is indeed a functional button at that location (many of my users did not know that clicking the corner will select all of the table cells). The 29th March 2007 posted by jpn was *extremely* helpful with a slight change. In jpn's example, he sets the button text in the TableWidget constructor like this:



btn->setText("Text");
opt.text = btn->text();


I set the button icon instead of the text:



QIcon myIcon = getMyIcon(); // this function returns a QIcon
btn->setIcon(myIcon);
opt.icon = btn->icon();


The "opt.text = btn->text();" line in the eventFilter function also has to be changed to "opt.icon = btn->icon();"

I also changed the functionality of the corner button. Instead of simply selecting all of the cells, I altered the corner button to toggle between selecting all the cells and clearing the selection.

Here is the relevant code from my QTableWidget constructor:



// Take the click signal off of the corner widget and replace it with our own
// This enables toggling the selection when the corner button is clicked.
// This is more ergonomic than the default behavior of only selecting all of the cells.
m_toggleCornerSelection = false;
QAbstractButton *btn = findChild<QAbstractButton *>();
if (btn != NULL) {
btn->disconnect(SIGNAL(clicked()));
connect(btn, SIGNAL(clicked()), this, SLOT(handleCornerButtonClicked()));
MyIcons *iconList = MyIcons::getIcons(); // our class that handles all of our icons
QIcon selectIcon = iconList->getIconSet(MyIcons::SELECT_ALL);
btn->setIcon(selectIcon);
// btn->setText("text");
btn->setToolTip("Toggle selecting all table cells");
btn->installEventFilter(this);

// adjust the width of the vertical header to match the preferred corner button width
// (unfortunately QAbstractButton doesn't implement any size hinting functionality)
QStyleOptionHeader opt;
// opt.text = btn->text();
opt.icon = btn->icon();
QSize s = (btn->style()->sizeFromContents(QStyle::CT_HeaderSection, &opt, QSize(), btn).
expandedTo(QApplication::globalStrut()));
if (s.isValid()) {
verticalHeader()->setMinimumWidth(s.width());
}
}


I then implemented the following code:



//-----------------------------------------------------------------------------
// Event filter used to draw an icon in the top-left corner of the table widget
//-----------------------------------------------------------------------------

bool MySpreadsheet::eventFilter(QObject* o, QEvent* e)
{
if (e->type() == QEvent::Paint) {
QAbstractButton* btn = qobject_cast<QAbstractButton*>(o);
if (btn) {
// paint by hand (borrowed from QTableCornerButton)
QStyleOptionHeader opt;
opt.init(btn);
QStyle::State styleState = QStyle::State_None;
if (btn->isEnabled())
styleState |= QStyle::State_Enabled;
if (btn->isActiveWindow())
styleState |= QStyle::State_Active;
if (btn->isDown())
styleState |= QStyle::State_Sunken;
opt.state = styleState;
opt.rect = btn->rect();
// opt.text = btn->text(); // this line is the only difference to QTableCornerButton
opt.icon = btn->icon(); // this line is the only difference to QTableCornerButton
opt.position = QStyleOptionHeader::OnlyOneSection;
QStylePainter painter(btn);
painter.drawControl(QStyle::CE_Header, opt);
return true; // eat event
}
}
return false;
}

...
//-----------------------------------------------------------------------------
// Handle clicking the upper-left corner button. This action toggles the selection of all of the cells
// off and on.
//-----------------------------------------------------------------------------

void MySpreadsheet::handleCornerButtonClicked()
{
if (m_toggleCornerSelection) {
clearSelection();
} else {
selectAll();
}
m_toggleCornerSelection = !m_toggleCornerSelection;
}



I hope that is helpful to those who want similar functionality.

Spookstaz
6th April 2011, 19:57
I am using PyQt and none of the above solutions worked for me. However I was able to successfully hide the button by sub-classing QTableView and overriding the updateGeometries function.



class MyTableView(QTableView):

def updateGeometries(self):
# Call the updateGeometries function defined by QTableView first
super(MyTableView, self).updateGeometries()
# Find the corner widget and hide it!
self.findChild(QAbstractButton).setHidden(True)

hvengel
31st May 2012, 00:44
I am trying to do something similar by changing the button icon. But I am using an icon the is not square. It is twice as wide as it is high. The icon is displayed but is not taking up the whole area of the button (I have set the header width to be twice as wide as it is high). To overcome this I am using:


btn->setIconSize(m_iconSize);
QPixmap pixmap = btn->icon().pixmap(m_iconSize, QIcon::Normal, QIcon::On);
QStylePainter painter(btn);
painter.drawItemPixmap(btn->rect(), Qt::AlignCenter, pixmap);

Instead of


btn->setIconSize(m_iconSize);
QStylePainter painter(btn);
painter.drawControl(QStyle::CE_Header, opt);

So that the icon pixmap is being directly drawn to the area where the control is. This works but not as well as I would like. Is there any way to force painter.drawControl() to draw the icon full size?